diff --git a/ServerlessLibraryAPI/ClientApp/src/App.js b/ServerlessLibraryAPI/ClientApp/src/App.js
index 087605d..c7889f3 100644
--- a/ServerlessLibraryAPI/ClientApp/src/App.js
+++ b/ServerlessLibraryAPI/ClientApp/src/App.js
@@ -1,7 +1,9 @@
import React, { Component } from 'react';
+import { Switch, Route } from 'react-router-dom';
import './App.css';
import { Header } from './components/Header';
+import { Login } from './components/Login';
class App extends Component {
constructor(props) {
@@ -21,9 +23,17 @@ getCurrentSample(id)
return (
-
- maincontent
-
+
+ {
+ return (
+
+ maincontent
+
+ );
+ }}
+ />
+
+
);
}
diff --git a/ServerlessLibraryAPI/ClientApp/src/components/Header/Header.js b/ServerlessLibraryAPI/ClientApp/src/components/Header/Header.js
index 23c8c9a..d550dbc 100644
--- a/ServerlessLibraryAPI/ClientApp/src/components/Header/Header.js
+++ b/ServerlessLibraryAPI/ClientApp/src/components/Header/Header.js
@@ -61,7 +61,8 @@ class Header extends Component {
user: {}
});
userService.getCurrentUser()
- .then(user => this.setState({ user }));
+ .then(user => this.setState({ user }))
+ .catch(error => console.log(error));
}
render() {
@@ -70,7 +71,7 @@ class Header extends Component {
Microsoft Azure
- {user.firstName !== '' &&
+ {user && user.firstName && user.firstName !== '' &&
{
+ let { from } = this.state;
+ window.location = `/api/user/login?returnUrl=${from.pathname}`;
+ }
+
+ render() {
+ let { from, redirectToReferrer } = this.state;
+
+ if (redirectToReferrer) {
+ return ;
+ }
+ return (
+
+
You must log in to view the page at {from.pathname}
+
Sign in
+
+
Sign out
+
+
+
+ )
+ }
+}
+
+export { Login };
diff --git a/ServerlessLibraryAPI/ClientApp/src/components/Login/index.js b/ServerlessLibraryAPI/ClientApp/src/components/Login/index.js
new file mode 100644
index 0000000..a10c3a8
--- /dev/null
+++ b/ServerlessLibraryAPI/ClientApp/src/components/Login/index.js
@@ -0,0 +1 @@
+export * from './Login';
diff --git a/ServerlessLibraryAPI/ClientApp/src/helpers/handle-response.js b/ServerlessLibraryAPI/ClientApp/src/helpers/handle-response.js
new file mode 100644
index 0000000..21e8c09
--- /dev/null
+++ b/ServerlessLibraryAPI/ClientApp/src/helpers/handle-response.js
@@ -0,0 +1,11 @@
+export function handleResponse(response) {
+ return response.text().then(text => {
+ const data = text && JSON.parse(text);
+ if (!response.ok) {
+ const error = (data && data.message) || response.statusText;
+ return Promise.reject(error);
+ }
+
+ return data;
+ })
+}
diff --git a/ServerlessLibraryAPI/ClientApp/src/helpers/index.js b/ServerlessLibraryAPI/ClientApp/src/helpers/index.js
new file mode 100644
index 0000000..6a28af2
--- /dev/null
+++ b/ServerlessLibraryAPI/ClientApp/src/helpers/index.js
@@ -0,0 +1 @@
+export * from './handle-response';
\ No newline at end of file
diff --git a/ServerlessLibraryAPI/ClientApp/src/services/user.service.js b/ServerlessLibraryAPI/ClientApp/src/services/user.service.js
index d1c629b..66475ac 100644
--- a/ServerlessLibraryAPI/ClientApp/src/services/user.service.js
+++ b/ServerlessLibraryAPI/ClientApp/src/services/user.service.js
@@ -1,14 +1,28 @@
+import { handleResponse } from '../helpers';
+
export const userService = {
getCurrentUser
};
-const dummyUser = {
- firstName: 'Nehaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
- lastName: 'Gupta',
- fullName: 'Neha Gupta',
- avatarUrl: 'https://github.com/msnehagup.png'
+const useFakeApi = true;
+
+const getFakeUser = () => {
+ return Promise.resolve({
+ fullName: 'Aaaaaaaaaaaaaaaaaaa Bbbbbbbbbbbb',
+ email: 'abc@xyz.com',
+ avatarUrl: 'https://avatars2.githubusercontent.com/u/45184761?v=4',
+ firstName: 'Aaaaaaaaaaaaaaaaaaa'
+ });
};
function getCurrentUser() {
- return Promise.resolve(dummyUser);
+ if (useFakeApi) {
+ return getFakeUser();
+ }
+
+ const requestOptions = {
+ method: 'GET'
+ };
+ return fetch('/api/user', requestOptions)
+ .then(handleResponse);
}
diff --git a/ServerlessLibraryAPI/Controllers/SampleDataController.cs b/ServerlessLibraryAPI/Controllers/SampleDataController.cs
deleted file mode 100644
index 6b94c9e..0000000
--- a/ServerlessLibraryAPI/Controllers/SampleDataController.cs
+++ /dev/null
@@ -1,44 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading.Tasks;
-using Microsoft.AspNetCore.Mvc;
-
-namespace ServerlessLibraryAPI.Controllers
-{
- [Route("api/[controller]")]
- public class SampleDataController : Controller
- {
- private static string[] Summaries = new[]
- {
- "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
- };
-
- [HttpGet("[action]")]
- public IEnumerable WeatherForecasts()
- {
- var rng = new Random();
- return Enumerable.Range(1, 5).Select(index => new WeatherForecast
- {
- DateFormatted = DateTime.Now.AddDays(index).ToString("d"),
- TemperatureC = rng.Next(-20, 55),
- Summary = Summaries[rng.Next(Summaries.Length)]
- });
- }
-
- public class WeatherForecast
- {
- public string DateFormatted { get; set; }
- public int TemperatureC { get; set; }
- public string Summary { get; set; }
-
- public int TemperatureF
- {
- get
- {
- return 32 + (int)(TemperatureC / 0.5556);
- }
- }
- }
- }
-}
diff --git a/ServerlessLibraryAPI/Controllers/UsersController.cs b/ServerlessLibraryAPI/Controllers/UsersController.cs
new file mode 100644
index 0000000..2b78dda
--- /dev/null
+++ b/ServerlessLibraryAPI/Controllers/UsersController.cs
@@ -0,0 +1,50 @@
+using Microsoft.AspNetCore.Authentication;
+using Microsoft.AspNetCore.Authentication.Cookies;
+using Microsoft.AspNetCore.Mvc;
+using ServerlessLibraryAPI.Models;
+
+namespace ServerlessLibraryAPI.Controllers
+{
+ [Route("api/[controller]")]
+ [ApiController]
+ public class UserController : ControllerBase
+ {
+ [HttpGet("login"), HttpPost("login")]
+ public IActionResult Login(string returnUrl = "/")
+ {
+ if (User.Identity.IsAuthenticated)
+ {
+ return new RedirectResult(returnUrl);
+ }
+
+ // Instruct the middleware corresponding to the requested external identity
+ // provider to redirect the user agent to its own authorization endpoint.
+ // Note: the authenticationScheme parameter must match the value configured in Startup.cs.
+ // If no scheme is provided then the DefaultChallengeScheme will be used
+ return Challenge(new AuthenticationProperties { RedirectUri = returnUrl });
+ }
+
+ [HttpGet("logout"), HttpPost("logout")]
+ public IActionResult Logout()
+ {
+ // Instruct the cookies middleware to delete the local cookie which
+ // was created after a successful authentication flow.
+ return SignOut(
+ new AuthenticationProperties { RedirectUri = "/" },
+ CookieAuthenticationDefaults.AuthenticationScheme);
+ }
+
+ [HttpGet]
+ [ProducesResponseType(typeof(GitHubUser), 200)]
+ public IActionResult Get()
+ {
+ if (User.Identity.IsAuthenticated)
+ {
+ GitHubUser user = new GitHubUser(User);
+ return Ok(user);
+ }
+
+ return Unauthorized();
+ }
+ }
+}
\ No newline at end of file
diff --git a/ServerlessLibraryAPI/Models/GitHubUser.cs b/ServerlessLibraryAPI/Models/GitHubUser.cs
new file mode 100644
index 0000000..3cf030b
--- /dev/null
+++ b/ServerlessLibraryAPI/Models/GitHubUser.cs
@@ -0,0 +1,33 @@
+using System.Security.Claims;
+using static ServerlessLibraryAPI.OAuth.GitHub.GitHubAuthenticationConstants;
+
+namespace ServerlessLibraryAPI.Models
+{
+ public class GitHubUser
+ {
+ public GitHubUser()
+ {
+ }
+
+ public GitHubUser(ClaimsPrincipal claimsPrincipal)
+ {
+ this.FullName = claimsPrincipal.FindFirstValue(Claims.Name);
+ this.Email = claimsPrincipal.FindFirstValue(ClaimTypes.Email);
+ this.AvatarUrl = claimsPrincipal.FindFirstValue(Claims.Avatar);
+ }
+
+ public string FullName { get; set; }
+
+ public string Email { get; set; }
+
+ public string AvatarUrl { get; set; }
+
+ public string FirstName
+ {
+ get
+ {
+ return this.FullName.Split(' ')?[0];
+ }
+ }
+ }
+}
diff --git a/ServerlessLibraryAPI/OAuth.GitHub/GitHubAuthenticationConstants.cs b/ServerlessLibraryAPI/OAuth.GitHub/GitHubAuthenticationConstants.cs
new file mode 100644
index 0000000..3e4e522
--- /dev/null
+++ b/ServerlessLibraryAPI/OAuth.GitHub/GitHubAuthenticationConstants.cs
@@ -0,0 +1,16 @@
+namespace ServerlessLibraryAPI.OAuth.GitHub
+{
+ ///
+ /// Contains constants specific to the .
+ ///
+ public static class GitHubAuthenticationConstants
+ {
+ public static class Claims
+ {
+ public const string Name = "urn:github:name";
+ public const string Url = "urn:github:url";
+ public const string Login = "urn:github:login";
+ public const string Avatar = "urn:github:avatar";
+ }
+ }
+}
diff --git a/ServerlessLibraryAPI/OAuth.GitHub/GitHubAuthenticationDefaults.cs b/ServerlessLibraryAPI/OAuth.GitHub/GitHubAuthenticationDefaults.cs
new file mode 100644
index 0000000..346f2a2
--- /dev/null
+++ b/ServerlessLibraryAPI/OAuth.GitHub/GitHubAuthenticationDefaults.cs
@@ -0,0 +1,58 @@
+namespace ServerlessLibraryAPI.OAuth.GitHub
+{
+ ///
+ /// Default values used by the GitHub authentication middleware.
+ ///
+ public static class GitHubAuthenticationDefaults
+ {
+ ///
+ /// Default value for .
+ ///
+ public const string AuthenticationScheme = "GitHub";
+
+ ///
+ /// Default value for .
+ ///
+ public const string DisplayName = "GitHub";
+
+ ///
+ /// Default value for .
+ ///
+ public const string Issuer = "GitHub";
+
+ ///
+ /// Default value for .
+ ///
+ public const string CallbackPath = "/signin-github";
+
+ ///
+ /// Default value for .
+ ///
+ public const string AuthorizationEndpoint = "https://github.com/login/oauth/authorize";
+
+ ///
+ /// Default value for .
+ ///
+ public const string TokenEndpoint = "https://github.com/login/oauth/access_token";
+
+ ///
+ /// Default value for .
+ ///
+ public const string UserInformationEndpoint = "https://api.github.com/user";
+
+ ///
+ /// Default value for .
+ ///
+ public const string UserEmailsEndpoint = "https://api.github.com/user/emails";
+
+ ///
+ /// Scope for .
+ ///
+ public const string UserInformationScope = "user";
+
+ ///
+ /// Scope for .
+ ///
+ public const string UserEmailsScope = "user:email";
+ }
+}
diff --git a/ServerlessLibraryAPI/OAuth.GitHub/GitHubAuthenticationHandler.cs b/ServerlessLibraryAPI/OAuth.GitHub/GitHubAuthenticationHandler.cs
new file mode 100644
index 0000000..714b63f
--- /dev/null
+++ b/ServerlessLibraryAPI/OAuth.GitHub/GitHubAuthenticationHandler.cs
@@ -0,0 +1,105 @@
+using System.Linq;
+using System.Net.Http;
+using System.Net.Http.Headers;
+using System.Security.Claims;
+using System.Text.Encodings.Web;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Authentication;
+using Microsoft.AspNetCore.Authentication.OAuth;
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Options;
+using Newtonsoft.Json.Linq;
+
+namespace ServerlessLibraryAPI.OAuth.GitHub
+{
+ public class GitHubAuthenticationHandler : OAuthHandler
+ {
+ public GitHubAuthenticationHandler(
+ IOptionsMonitor options,
+ ILoggerFactory logger,
+ UrlEncoder encoder,
+ ISystemClock clock)
+ : base(options, logger, encoder, clock)
+ {
+ }
+
+ protected override async Task CreateTicketAsync(ClaimsIdentity identity,
+ AuthenticationProperties properties, OAuthTokenResponse tokens)
+ {
+ var request = new HttpRequestMessage(HttpMethod.Get, Options.UserInformationEndpoint);
+ request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
+ request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", tokens.AccessToken);
+
+ var response = await Backchannel.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, Context.RequestAborted);
+ if (!response.IsSuccessStatusCode)
+ {
+ Logger.LogError("An error occurred while retrieving the user profile: the remote server " +
+ "returned a {Status} response with the following payload: {Headers} {Body}.",
+ /* Status: */ response.StatusCode,
+ /* Headers: */ response.Headers.ToString(),
+ /* Body: */ await response.Content.ReadAsStringAsync());
+
+ throw new HttpRequestException("An error occurred while retrieving the user profile.");
+ }
+
+ var payload = JObject.Parse(await response.Content.ReadAsStringAsync());
+
+ var principal = new ClaimsPrincipal(identity);
+ var context = new OAuthCreatingTicketContext(principal, properties, Context, Scheme, Options, Backchannel, tokens, payload);
+
+ context.RunClaimActions(payload);
+
+ // When the email address is not public, retrieve it from
+ // the emails endpoint if the user:email scope is specified.
+ if (!string.IsNullOrEmpty(Options.UserEmailsEndpoint) &&
+ !identity.HasClaim(claim => claim.Type == ClaimTypes.Email) && Options.Scope.Contains("user:email"))
+ {
+ var address = await GetEmailAsync(tokens);
+ if (!string.IsNullOrEmpty(address))
+ {
+ identity.AddClaim(new Claim(ClaimTypes.Email, address, ClaimValueTypes.String, Options.ClaimsIssuer));
+ }
+ }
+
+ await Options.Events.CreatingTicket(context);
+ return new AuthenticationTicket(context.Principal, context.Properties, Scheme.Name);
+ }
+
+ protected virtual async Task GetEmailAsync(OAuthTokenResponse tokens)
+ {
+ // See https://developer.github.com/v3/users/emails/ for more information about the /user/emails endpoint.
+ var request = new HttpRequestMessage(HttpMethod.Get, Options.UserEmailsEndpoint);
+ request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
+ request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", tokens.AccessToken);
+
+ // Failed requests shouldn't cause an error: in this case, return null to indicate that the email address cannot be retrieved.
+ var response = await Backchannel.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, Context.RequestAborted);
+ if (!response.IsSuccessStatusCode)
+ {
+ Logger.LogWarning("An error occurred while retrieving the email address associated with the logged in user: " +
+ "the remote server returned a {Status} response with the following payload: {Headers} {Body}.",
+ /* Status: */ response.StatusCode,
+ /* Headers: */ response.Headers.ToString(),
+ /* Body: */ await response.Content.ReadAsStringAsync());
+
+ return null;
+ }
+
+ var payload = JArray.Parse(await response.Content.ReadAsStringAsync());
+
+ return (from address in payload.AsJEnumerable()
+ where address.Value("primary")
+ select address.Value("email")).FirstOrDefault();
+ }
+
+ protected override Task HandleAuthenticateAsync()
+ {
+ return base.HandleAuthenticateAsync();
+ }
+
+ protected override Task HandleRemoteAuthenticateAsync()
+ {
+ return base.HandleRemoteAuthenticateAsync();
+ }
+ }
+}
diff --git a/ServerlessLibraryAPI/OAuth.GitHub/GitHubAuthenticationOptions.cs b/ServerlessLibraryAPI/OAuth.GitHub/GitHubAuthenticationOptions.cs
new file mode 100644
index 0000000..ddf5bde
--- /dev/null
+++ b/ServerlessLibraryAPI/OAuth.GitHub/GitHubAuthenticationOptions.cs
@@ -0,0 +1,41 @@
+using System.Security.Claims;
+using Microsoft.AspNetCore.Authentication;
+using Microsoft.AspNetCore.Authentication.OAuth;
+using Microsoft.AspNetCore.Http;
+using static ServerlessLibraryAPI.OAuth.GitHub.GitHubAuthenticationConstants;
+
+namespace ServerlessLibraryAPI.OAuth.GitHub
+{
+ ///
+ /// Defines a set of options used by .
+ ///
+ public class GitHubAuthenticationOptions : OAuthOptions
+ {
+ public GitHubAuthenticationOptions()
+ {
+ ClaimsIssuer = GitHubAuthenticationDefaults.Issuer;
+
+ CallbackPath = new PathString(GitHubAuthenticationDefaults.CallbackPath);
+
+ AuthorizationEndpoint = GitHubAuthenticationDefaults.AuthorizationEndpoint;
+ TokenEndpoint = GitHubAuthenticationDefaults.TokenEndpoint;
+ UserInformationEndpoint = GitHubAuthenticationDefaults.UserInformationEndpoint;
+ //Scope.Add(GitHubAuthenticationDefaults.UserInformationScope);
+ Scope.Add(GitHubAuthenticationDefaults.UserEmailsScope);
+
+ ClaimActions.MapJsonKey(ClaimTypes.NameIdentifier, "id");
+ ClaimActions.MapJsonKey(ClaimTypes.Name, "login");
+ ClaimActions.MapJsonKey(ClaimTypes.Email, "email");
+ ClaimActions.MapJsonKey(Claims.Name, "name");
+ ClaimActions.MapJsonKey(Claims.Url, "html_url");
+ ClaimActions.MapJsonKey(Claims.Login, "login");
+ ClaimActions.MapJsonKey(Claims.Avatar, "avatar_url");
+ }
+
+ ///
+ /// Gets or sets the address of the endpoint exposing
+ /// the email addresses associated with the logged in user.
+ ///
+ public string UserEmailsEndpoint { get; set; } = GitHubAuthenticationDefaults.UserEmailsEndpoint;
+ }
+}
diff --git a/ServerlessLibraryAPI/Properties/launchSettings.json b/ServerlessLibraryAPI/Properties/launchSettings.json
index 13fbfb9..5a69813 100644
--- a/ServerlessLibraryAPI/Properties/launchSettings.json
+++ b/ServerlessLibraryAPI/Properties/launchSettings.json
@@ -15,6 +15,14 @@
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
+ "IIS Express - API only": {
+ "commandName": "IISExpress",
+ "launchBrowser": true,
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development",
+ "ApiOnly": "true"
+ }
+ },
"ServerLessLibrary": {
"commandName": "Project",
"launchBrowser": true,
diff --git a/ServerlessLibraryAPI/ServerlessLibraryAPI.csproj b/ServerlessLibraryAPI/ServerlessLibraryAPI.csproj
index 990c0a0..0339026 100644
--- a/ServerlessLibraryAPI/ServerlessLibraryAPI.csproj
+++ b/ServerlessLibraryAPI/ServerlessLibraryAPI.csproj
@@ -9,6 +9,7 @@
$(DefaultItemExcludes);$(SpaRoot)node_modules\**
/subscriptions/7c1b7bab-00b2-4cb7-924e-205c4f411810/resourcegroups/Default-ApplicationInsights-EastUS/providers/microsoft.insights/components/ServerlessLibrary
/subscriptions/7c1b7bab-00b2-4cb7-924e-205c4f411810/resourcegroups/Default-ApplicationInsights-EastUS/providers/microsoft.insights/components/ServerlessLibrary
+ 235c2497-239d-47f0-8ea7-af2dd2416d95
diff --git a/ServerlessLibraryAPI/ServerlessLibrarySettings.cs b/ServerlessLibraryAPI/ServerlessLibrarySettings.cs
index 6d8ea20..34ebb8e 100644
--- a/ServerlessLibraryAPI/ServerlessLibrarySettings.cs
+++ b/ServerlessLibraryAPI/ServerlessLibrarySettings.cs
@@ -25,6 +25,7 @@ namespace ServerlessLibrary
public static string CosmosAuthkey { get { return config(); } }
public static string Database { get { return "serverlesslibrary"; } }
public static string Collection { get { return "contributions"; } }
+ public static bool ApiOnly { get { return Boolean.Parse(config("false")); } }
}
}
diff --git a/ServerlessLibraryAPI/Startup.cs b/ServerlessLibraryAPI/Startup.cs
index fb36e83..1681b4f 100644
--- a/ServerlessLibraryAPI/Startup.cs
+++ b/ServerlessLibraryAPI/Startup.cs
@@ -1,9 +1,11 @@
+using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.SpaServices.ReactDevelopmentServer;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
+using ServerlessLibraryAPI.OAuth.GitHub;
using Swashbuckle.AspNetCore.Swagger;
namespace ServerlessLibrary
@@ -22,6 +24,20 @@ namespace ServerlessLibrary
{
services.AddMemoryCache();
+ services.AddAuthentication(options =>
+ {
+ options.DefaultChallengeScheme = GitHubAuthenticationDefaults.AuthenticationScheme;
+ options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
+ })
+ .AddCookie()
+ .AddOAuth(
+ GitHubAuthenticationDefaults.AuthenticationScheme,
+ GitHubAuthenticationDefaults.DisplayName,
+ options => {
+ options.ClientId = Configuration["Authentication:GitHub:ClientId"]; // these settings need to be present in appSettings (or in secrets.json)
+ options.ClientSecret = Configuration["Authentication:GitHub:ClientSecret"];
+ });
+
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
// In production, the React files will be served from this directory
@@ -56,7 +72,6 @@ namespace ServerlessLibrary
app.UseHsts();
}
- app.UseHttpsRedirection();
app.UseDefaultFiles();
app.UseStaticFiles();
app.UseSpaStaticFiles();
@@ -67,6 +82,8 @@ namespace ServerlessLibrary
c.RoutePrefix = "swagger";
});
+ app.UseAuthentication();
+
app.UseMvc(routes =>
{
routes.MapRoute(
@@ -74,15 +91,18 @@ namespace ServerlessLibrary
template: "{controller}/{action=Index}/{id?}");
});
- app.UseSpa(spa =>
+ if (!ServerlessLibrarySettings.ApiOnly)
{
- spa.Options.SourcePath = "ClientApp";
-
- if (env.IsDevelopment())
+ app.UseSpa(spa =>
{
- spa.UseReactDevelopmentServer(npmScript: "start");
- }
- });
+ spa.Options.SourcePath = "ClientApp";
+
+ if (env.IsDevelopment())
+ {
+ spa.UseReactDevelopmentServer(npmScript: "start");
+ }
+ });
+ }
app.Use(async (context, next) =>
{
diff --git a/ServerlessLibraryAPI/appsettings.Development.json b/ServerlessLibraryAPI/appsettings.Development.json
index e203e94..235d51e 100644
--- a/ServerlessLibraryAPI/appsettings.Development.json
+++ b/ServerlessLibraryAPI/appsettings.Development.json
@@ -5,5 +5,8 @@
"System": "Information",
"Microsoft": "Information"
}
+ },
+ "ApplicationInsights": {
+ "InstrumentationKey": ""
}
}
diff --git a/ServerlessLibraryAPI/appsettings.json b/ServerlessLibraryAPI/appsettings.json
index 5da4926..11313b9 100644
--- a/ServerlessLibraryAPI/appsettings.json
+++ b/ServerlessLibraryAPI/appsettings.json
@@ -7,5 +7,11 @@
"AllowedHosts": "*",
"ApplicationInsights": {
"InstrumentationKey": "d35b5caf-a276-467c-9ac7-f7f7d84ea171"
+ },
+ "Authentication": {
+ "GitHub": {
+ "ClientId": "",
+ "ClientSecret": ""
+ }
}
}
\ No newline at end of file