how to redirect from /signin-oidc back to my controller/action? - asp.net-core

the callback url is https://localhost:44338/signin-oidc
lets say i am in controller/action , decorated with [Authorize]
how do i redirect from https://localhost:44338/signin-oidc back to my controller/action ?
Note : I am following the wiki :
Quickstart: Add sign-in with Microsoft to an ASP.NET Core web app

You can store the url on server side . For example ,base on code sample :
Quickstart: Add sign-in with Microsoft to an ASP.NET Core web app
modify your OIDC configurations like :
services.AddAuthentication(AzureADDefaults.AuthenticationScheme)
.AddAzureAD(options => Configuration.Bind("AzureAd", options));
services.Configure<OpenIdConnectOptions>(AzureADDefaults.OpenIdScheme, options =>
{
options.Authority = options.Authority + "/v2.0/";
options.Events = new OpenIdConnectEvents
{
OnRedirectToIdentityProvider = async n =>
{
//save url to state
n.ProtocolMessage.State = n.HttpContext.Request.Path.Value.ToString();
},
OnTokenValidated = ctx =>
{
var url = ctx.ProtocolMessage.GetParameter("state");
var claims = new List<Claim>
{
new Claim("myurl", url)
};
var appIdentity = new ClaimsIdentity(claims);
//add url to claims
ctx.Principal.AddIdentity(appIdentity);
return Task.CompletedTask;
},
OnTicketReceived = ctx =>
{
var url = ctx.Principal.FindFirst("myurl").Value;
ctx.ReturnUri = url;
return Task.CompletedTask;
}
};
// Per the code below, this application signs in users in any Work and School
// accounts and any Microsoft Personal Accounts.
// If you want to direct Azure AD to restrict the users that can sign-in, change
// the tenant value of the appsettings.json file in the following way:
// - only Work and School accounts => 'organizations'
// - only Microsoft Personal accounts => 'consumers'
// - Work and School and Personal accounts => 'common'
// If you want to restrict the users that can sign-in to only one tenant
// set the tenant value in the appsettings.json file to the tenant ID of this
// organization, and set ValidateIssuer below to true.
// If you want to restrict the users that can sign-in to several organizations
// Set the tenant value in the appsettings.json file to 'organizations', set
// ValidateIssuer, above to 'true', and add the issuers you want to accept to the
// options.TokenValidationParameters.ValidIssuers collection
options.TokenValidationParameters.ValidateIssuer = false;
});

Related

The mandatory 'code_challenge' parameter is missing with OpenIddict

I have an identity server running asp.net core 5, with openiddict 3.1.1
I'm having trouble where I'm getting the error from openiddict:
error:invalid_request
error_description:The mandatory 'code_challenge' parameter is missing.
error_uri:https://documentation.openiddict.com/errors/ID2029
in some scenarios, but not all. My identity server has a startup.cs of:
services.AddDbContext<IdentityContext>(options =>
{
options.UseSqlServer(dbConnectionString, x => x.UseNetTopologySuite());
// Register the entity sets needed by OpenIddict.
// Note: use the generic overload if you need
// to replace the default OpenIddict entities.
options.UseOpenIddict<Guid>();
});
services.AddTransient<IPasswordHasher<ApplicationUser>, CustomPasswordHasher>();
services.AddTransient<IOptions<IdentityOptions>, CustomOptions>();
services.AddScoped<SignInManager<ApplicationUser>, CustomSignInManager>();
services.AddIdentity<ApplicationUser, ApplicationRole>()
.AddEntityFrameworkStores<IdentityContext>()
//.AddDefaultUI()
.AddDefaultTokenProviders();
services.AddOpenIddict()
// Register the OpenIddict core components.
.AddCore(options =>
{
// Configure OpenIddict to use the Entity Framework Core stores and models.
// Note: call ReplaceDefaultEntities() to replace the default entities.
options.UseEntityFrameworkCore()
.UseDbContext<IdentityContext>()
.ReplaceDefaultEntities<Guid>();
})
// Register the OpenIddict server components.
.AddServer(options =>
{
// Enable the authorization, device, logout, token, userinfo and verification endpoints.
options.SetAuthorizationEndpointUris("/connect/authorize")
.SetLogoutEndpointUris("/connect/signout")
.SetTokenEndpointUris("/connect/token");
// Enable the client credentials flow.
options
.AllowAuthorizationCodeFlow().RequireProofKeyForCodeExchange()
.AllowRefreshTokenFlow();
// Encryption and signing of tokens
options
.AddEphemeralEncryptionKey()
.AddEphemeralSigningKey()
.DisableAccessTokenEncryption(); //TODO: not a huge deal as long as we're not hiding anything bad here.
// Expose all the supported claims in the discovery document.
options.RegisterClaims(Configuration.GetSection("OpenIddict:Claims").Get<string[]>());
// Expose all the supported scopes in the discovery document.
options.RegisterScopes(Configuration.GetSection("OpenIddict:Scopes").Get<string[]>());
// Register the ASP.NET Core host and configure the ASP.NET Core-specific options.
options.UseAspNetCore()
.EnableStatusCodePagesIntegration()
.EnableAuthorizationEndpointPassthrough()
.EnableAuthorizationRequestCaching()
.EnableLogoutEndpointPassthrough()
.EnableVerificationEndpointPassthrough()
.EnableTokenEndpointPassthrough();
})
// Register the OpenIddict validation components.
.AddValidation(options =>
{
// Import the configuration from the local OpenIddict server instance.
options.UseLocalServer();
// Register the ASP.NET Core host.
options.UseAspNetCore();
// Enable authorization entry validation, which is required to be able
// to reject access tokens retrieved from a revoked authorization code.
options.EnableAuthorizationEntryValidation();
});
with an OpenIDWorker of:
public async Task StartAsync(CancellationToken cancellationToken)
{
using IServiceScope scope = _serviceProvider.CreateScope();
IdentityContext context = scope.ServiceProvider.GetRequiredService<IdentityContext>();
await RegisterApplicationsAsync(scope.ServiceProvider, _configuration);
static async Task RegisterApplicationsAsync(IServiceProvider provider, IConfiguration configuration)
{
IOpenIddictApplicationManager manager = provider.GetRequiredService<IOpenIddictApplicationManager>();
string clientID = configuration.GetSection("OpenIddict:ClientId").Get<string>();
string clientSecretString = "blahblahblah";
if (await manager.FindByClientIdAsync(clientID) is null)
{
await manager.CreateAsync(new OpenIddictApplicationDescriptor
{
ClientId = clientID,
ClientSecret = clientSecretString,
ConsentType = ConsentTypes.Explicit,
DisplayName = configuration.GetSection("OpenIddict:DisplayName").Get<string>(),
PostLogoutRedirectUris =
{
new Uri("https://localhost:44330/signout-callback-oidc")
},
RedirectUris =
{
new Uri("https://localhost:44330/signin-oidc")
},
Permissions =
{
Permissions.Endpoints.Authorization,
Permissions.Endpoints.Logout,
Permissions.Endpoints.Token,
Permissions.GrantTypes.AuthorizationCode,
Permissions.GrantTypes.RefreshToken,
Permissions.ResponseTypes.Code,
Permissions.Scopes.Email,
Permissions.Scopes.Profile,
Permissions.Scopes.Roles,
},
Requirements =
{
Requirements.Features.ProofKeyForCodeExchange
}
});
}
}
}
when i try to connect to the server with a C# razor app with the following startup.cs, it works fine and w/out any issues:
string clientSecretString = "blahblahblah";
services.AddAuthentication(options =>
{
options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
}).AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, options =>
{
options.LoginPath = "/login";
options.ExpireTimeSpan = TimeSpan.FromMinutes(50);
options.SlidingExpiration = false;
})
.AddOpenIdConnect(OpenIdConnectDefaults.AuthenticationScheme, options =>
{
// Note: these settings must match the application details
// inserted in the database at the server level.
options.ClientId = Configuration.GetSection("ClientId").Get<string>();
options.ClientSecret = clientSecretString;
options.RequireHttpsMetadata = false;
options.GetClaimsFromUserInfoEndpoint = true;
options.SaveTokens = true;
// Use the authorization code flow.
options.ResponseType = OpenIdConnectResponseType.Code;
options.AuthenticationMethod = OpenIdConnectRedirectBehavior.RedirectGet;
// Note: setting the Authority allows the OIDC client middleware to automatically
// retrieve the identity provider's configuration and spare you from setting
// the different endpoints URIs or the token validation parameters explicitly.
options.Authority = "https://localhost:44330/";
options.Scope.Add("email");
options.Scope.Add("roles");
options.Scope.Add("offline_access");
options.SecurityTokenValidator = new JwtSecurityTokenHandler
{
// Disable the built-in JWT claims mapping feature.
InboundClaimTypeMap = new Dictionary<string, string>()
};
options.TokenValidationParameters.NameClaimType = "name";
options.TokenValidationParameters.RoleClaimType = "role";
options.AccessDeniedPath = "/";
});
But when i try to connect to it with https://oidcdebugger.com/, or if I try to connect to it using Azure B2C user flows, I get the error message above about missing a code_challenge (see image )
What am i missing here? My plan was to use B2C, but i'm not seeing what is blocking me.
See https://github.com/openiddict/openiddict-core/issues/1361 for reference. Issue ended up being a problem with B2C itself, and will require a fix for them

ASP.NET Core 3.1 Use both OpenIDConnect and Custom Cookie Authentication

I have an existing application that makes use of Cookie Authentication, and would like to add the ability to authenticate users using Active Directory. The current application uses Cookie based authentication and custom authorisation - roles in a database.
I am adding bits from example located here:
Add sign-in with Microsoft to an ASP.NET Core web app
When I run the application I get an error:
System.InvalidOperationException: Scheme already exists: Cookies
What is the correct way to configure OpenIdConnect and Cookie Authentication.
// STEP 1 Basic Cookie Auth
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
.AddCookie(options =>
{
options.LoginPath = "/Auth";
options.AccessDeniedPath = "/Home/AccessDenied";
options.Cookie.IsEssential = true;
options.SlidingExpiration = true;
options.ExpireTimeSpan = TimeSpan.FromSeconds(day/2.0);
options.Cookie.HttpOnly = true; // not accessible via JavaScript
options.Cookie.Name = "login_token";
options.TicketDataFormat = new CustomJwtDataFormat(
SecurityAlgorithms.HmacSha256,
tokenValidationParameters);
});
// STEP 2 OpenID Connect Auth
services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApp(Configuration.GetSection("AzureAd"), "OpenIdConnect", "Cookies", true);
I am not able to find any examples using both Cookie Authentication and OpenID Connect. Is this possible? Allowing users to login selectively using Active Directory authentication, or local authentication (details stored in local database).
After changing the "Cookie" name, get's rid of the error message,
but breaks the local authorisation, e.g.
When a valid Username and Password is given, I typically
authorise the login.
HttpContext.Response.Cookies.Append("login_token", token, GetCookieOptions());
Currently with OpenIDConnect configured User.Identity.IsAuthenticated
remains false.
According to the error messages, it tell you that you have multiple Scheme which named cookies.
According to the AddMicrosoftIdentityWebApp Method document, you could find the third parameter name is the cookieScheme.
The cookie-based scheme name to be used. By default it uses "Cookies".
But you have already set this name at above, so you should use other one. For example: "ADCookies".
Like below:
services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApp(Configuration.GetSection("AzureAd"), "OpenIdConnect", "ADCookies", true);
The mixed approach is a minefield but the below is allowing use to Authenticate Users via IdentityServer4 using OIDC while authenticating the Application into AzureAD with Identity.Web to get tokens for Api calls.
services.AddAuthentication(options =>
{
options.DefaultScheme = "IS4Cookies";
options.DefaultChallengeScheme = "oidc";
})
.AddCookie("IS4Cookies")
.AddOpenIdConnect("oidc", "OpenID Connect", options =>
{
options.SignInScheme = "IS4Cookies";
// Get IdentityServer configuration from appsettings.json.
var config = Configuration.GetSection("IdentityServerOptions").Get<IdentityServerOptions>();
options.Authority = config.Authority;
options.RequireHttpsMetadata = false;
options.ClientId = config.ClientId;
options.ClientSecret = config.ClientSecret;
options.ResponseType = "code";
options.SaveTokens = true;
options.GetClaimsFromUserInfoEndpoint = true;
options.ClaimActions.MapJsonKey("role", "role");
options.ClaimActions.MapJsonKey("role", System.Security.Claims.ClaimTypes.Role);
options.ClaimActions.MapJsonKey("email", "email");
options.ClaimActions.MapJsonKey("preferred_username", "preferred_username");
options.Events = new OpenIdConnectEvents
{
OnRemoteFailure = context =>
{
context.Response.Redirect("/");
context.HandleResponse();
return Task.FromResult(0);
}
};
})
.AddMicrosoftIdentityWebApp(Configuration, "AzureOptions")
.EnableTokenAcquisitionToCallDownstreamApi(new string[]{"sms.all" })
.AddInMemoryTokenCaches();
This is what I use and it works, you just need to specify the configureCookieAuthenticationOptions and set the name inside there and you should be good to go, also I had to use lax for SameSite or it would not work for me.
services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApp(identityOptions =>
/* {identityOptions.ClientId ="";}, // if you want to specify the options manually instead of Configuration.GetSection() call*/
Configuration.GetSection("AzureAd"),
configureCookieAuthenticationOptions: authCookie => { // Setup SSO cookie
authCookie.Cookie.Name ="Your.Cookie.Name.Here";// change name to hide .net identifiers in name
authCookie.Cookie.HttpOnly = true;// make so client cannot alter cookie
authCookie.Cookie.SecurePolicy = CookieSecurePolicy.Always;// require https
authCookie.Cookie.SameSite = SameSiteMode.Lax;// from external resource
// verify options are valid or throw exception
authCookie.Validate();
}
);
You may or may not need all of the authCookie values here, but it should get you started in the right direction!
It's possible to mix two mechanisms.
I use MicrosoftIdentity authentication for access to administration web pages and cookies authentication for my APIs and SignalR hubs.
I use this in startup ConfigureServices
services
.AddAuthentication(sharedOptions =>
{
sharedOptions.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
sharedOptions.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
sharedOptions.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
})
.AddCookie("CookiesApiScheme", options =>
{
options.SlidingExpiration = true;
// There is no redirection to a login page for APIs and SignalR Hubs, I just made a call to /Api/Login/SignIn with credential
options.AccessDeniedPath = new PathString("/Api/Login/AccessDenied"); // Action who just returns an Unauthorized
})
.AddMicrosoftIdentityWebApp(Configuration); // By default scheme is "CookieAuthenticationDefaults.AuthenticationScheme"
And in API controller you can use something like this
[Route("api/[controller]")]
[ApiController]
[Authorize(Roles = Roles.ADMIN)]
[Authorize(AuthenticationSchemes = "CookiesApiScheme")]
public class DefaultController : ControllerBase
{
[HttpGet]
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
}
Based on this post: ASP.NET Core 2.0 AzureAD Authentication not working

How to setup WASM IdentityServer with user/pass authentication AND device authentication with client/secret from a console application

I have a typical Blazor WASM project, Server, Client and Shared. Authentication with IdentityServer is setup and working correctly. I'm receiving the JWT when I login with a user and I can get the discovery document.
Aside from normal users, I want to connect devices. These devices are not users so it seems wrong to create a user for each device. If I create a user then I can login and get the token. But I added InMemoryClients, so I was under the assumption that I could login as a client with id/secret using the device authentication endpoint of the discovery document.
I added a console application that is running on the device. But authentication fails returning "invalid_client".
In the server app I defined a Client and ApiScope:
public static IEnumerable<ApiScope> ApiScopes =>
new List<ApiScope>
{
new ApiScope("api", "My API")
};
public static IEnumerable<IdentityServer4.Models.Client> Clients =>
new List<IdentityServer4.Models.Client>
{
new IdentityServer4.Models.Client
{
ClientId = "device",
// no interactive user, use the clientid/secret for authentication
AllowedGrantTypes = GrantTypes.ClientCredentials,
// secret for authentication
ClientSecrets =
{
new Secret("secret")
},
// scopes that client has access to
AllowedScopes = { "api" }
}
};
They are added with the AddInMemory functions in the Startup.Configure method:
services.AddIdentityServer()
.AddInMemoryApiScopes(Config.ApiScopes)
.AddInMemoryClients(Config.Clients)
.AddApiAuthorization<ApplicationUser, ApplicationDbContext>(options =>
{
options.IdentityResources["openid"].UserClaims.Add("name");
options.ApiResources.Single().UserClaims.Add("name");
options.IdentityResources["openid"].UserClaims.Add("role");
options.ApiResources.Single().UserClaims.Add("role");
});
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Remove("role");
services.AddAuthentication("Bearer")
.AddJwtBearer("Bearer", options =>
{
options.Authority = "https://localhost:44316";
options.Audience = "api";
})
.AddIdentityServerJwt();
In the console app I send a DeviceAuthenticationRequest:
static IDiscoveryCache _cache = new DiscoveryCache("https://localhost:44316");
var disco = await _cache.GetAsync();
if (disco.IsError) throw new Exception(disco.Error);
var client = new HttpClient();
response = await client.RequestDeviceAuthorizationAsync(new DeviceAuthorizationRequest
{
//Address = disco.TokenEndPoint, // same result
Address = disco.DeviceAuthorizationEndpoint,
ClientId = "device",
ClientSecret = "secret",
Scope = "api"
});
The response in the client contains an error, "invalid_client". And the server complains also:
IdentityServer4.Validation.ClientSecretValidator: Error: No client with id 'client' found. aborting
I hope my question is clear, thanks in advance.
EDIT
Obviously the typo was a problem. But I managed to fix it by changing the AllowedGrantTypes to:
AllowedGrantTypes = { GrantTypes.ClientCredentials, GrantTypes.DeviceFlow };
However! I had to removed api authorization, need to figure out how to add it back:
.AddApiAuthorization<ApplicationUser, ApplicationDbContext>(options =>
{
options.IdentityResources["openid"].UserClaims.Add("name");
options.ApiResources.Single().UserClaims.Add("name");
options.IdentityResources["openid"].UserClaims.Add("role");
options.ApiResources.Single().UserClaims.Add("role");
});
And instead of specifying options for and adding JwtBearer:
//services.AddAuthentication("Bearer")
// .AddJwtBearer("Bearer", options =>
// {
// options.Authority = "https://localhost:44316";
// options.Audience = "api";
// })
// .AddIdentityServerJwt();
I just have this:
services.AddAuthentication()
.AddIdentityServerJwt();
I think you have just a small typo. In the Startup.cs the ClientId = "device". In your client, you set ClientId = "client".
In general, you are right. You don't need to create a client for each user and their potential devices. The definition of one client for all possible users and devices is enough. You could even debate if a client's password is necessary and increase security. In the official docs, the secret is optional.
In a simplified view: the "client part" of this authentication flow is mainly used to generate the user code. In a second (asynchronous) step, a user with different device logins to authenticate the device by entering the previously generated code.
For more details of a look at this post.

ASP.NET Core authentication with Google only for a specific account

In my ASP.NET Core 3 app, I'd like to implement login with Google and only allow authentication for specific user(s).
What I did so far is to follow the tutorial from:
https://learn.microsoft.com/en-us/aspnet/core/security/authentication/social/social-without-identity?view=aspnetcore-3.0
https://learn.microsoft.com/en-us/aspnet/core/security/authentication/social/google-logins?view=aspnetcore-3.0
What are the next steps to make the user authorized only for specific Google account(s)?
Even if the user is authenticated successfully by Google, I want only specific Google account(s) (email addresses) to have access to my ASP.NET Core app.
What I tried was to set a delegate to the 'OnCreatingEvent' event, but I don't know how to reject authorization.
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication(options =>
{
options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = GoogleDefaults.AuthenticationScheme;
})
.AddCookie()
.AddGoogle(options =>
{
options.ClientId = Configuration["google-credentials:ClientId"];
options.ClientSecret = Configuration["google-credentials:ClientSecret"];
options.Events = new OAuthEvents()
{
OnCreatingTicket = HandleOnCreatingTicket
};
});
private async Task HandleOnCreatingTicket(OAuthCreatingTicketContext context)
{
var user = context.Identity;
if (user.Claims.FirstOrDefault(m => m.Type == ClaimTypes.Email).Value != "MY ACCOUNT")
{
// How to reject authorization?
}
await Task.CompletedTask;
}
You can create a policy to check whether user's name claim is in your allowed user name list , return true/false base on your validation result :
services.AddAuthorization(options =>
{
options.AddPolicy("AllowedUsersOnly", policy =>
{
policy.RequireAssertion(context =>
{
//Here you can get many resouces from context, i get a claim here for example
var name = context.User.Claims.FirstOrDefault(x => x.Type == ClaimTypes.Name)?.Value;
//write your logic to check user name .
return false;
});
});
});
Then you could apply policy on your controller/action or register global filter .

ASP.NET CORE WEB API authentication via Social Network

I have to build WEB api application that can authenticate user via Socail network like Facebook.
I understand how it's happening in asp.net core mvc, but I have no idea how it's happening in Web API. I find resource that build LinkedIn authentication in Startup.cs with code like this
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AutomaticAuthenticate = true,
AutomaticChallenge = true,
LoginPath = new PathString("/login"),
LogoutPath = new PathString("/logout")
});
app.UseOAuthAuthentication(new OAuthOptions
{
// We need to specify an Authentication Scheme
AuthenticationScheme = "LinkedIn",
// Configure the LinkedIn Client ID and Client Secret
ClientId = Configuration["linkedin:clientId"],
ClientSecret = Configuration["linkedin:clientSecret"],
// Set the callback path, so LinkedIn will call back to http://APP_URL/signin-linkedin
// Also ensure that you have added the URL as an Authorized Redirect URL in your LinkedIn application
CallbackPath = new PathString("/signin-linkedin"),
// Configure the LinkedIn endpoints
AuthorizationEndpoint = "https://www.linkedin.com/oauth/v2/authorization",
TokenEndpoint = "https://www.linkedin.com/oauth/v2/accessToken",
UserInformationEndpoint = "https://api.linkedin.com/v1/people/~:(id,formatted-name,email-address,picture-url)",
Scope = { "r_basicprofile", "r_emailaddress" },
Events = new OAuthEvents
{
// The OnCreatingTicket event is called after the user has been authenticated and the OAuth middleware has
// created an auth ticket. We need to manually call the UserInformationEndpoint to retrieve the user's information,
// parse the resulting JSON to extract the relevant information, and add the correct claims.
OnCreatingTicket = async context =>
{
// Retrieve user info
var request = new HttpRequestMessage(HttpMethod.Get, context.Options.UserInformationEndpoint);
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", context.AccessToken);
request.Headers.Add("x-li-format", "json"); // Tell LinkedIn we want the result in JSON, otherwise it will return XML
var response = await context.Backchannel.SendAsync(request, context.HttpContext.RequestAborted);
response.EnsureSuccessStatusCode();
// Extract the user info object
var user = JObject.Parse(await response.Content.ReadAsStringAsync());
// Add the Name Identifier claim
var userId = user.Value<string>("id");
if (!string.IsNullOrEmpty(userId))
{
context.Identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, userId, ClaimValueTypes.String, context.Options.ClaimsIssuer));
}
// Add the Name claim
var formattedName = user.Value<string>("formattedName");
if (!string.IsNullOrEmpty(formattedName))
{
context.Identity.AddClaim(new Claim(ClaimTypes.Name, formattedName, ClaimValueTypes.String, context.Options.ClaimsIssuer));
}
// Add the email address claim
var email = user.Value<string>("emailAddress");
if (!string.IsNullOrEmpty(email))
{
context.Identity.AddClaim(new Claim(ClaimTypes.Email, email, ClaimValueTypes.String,
context.Options.ClaimsIssuer));
}
// Add the Profile Picture claim
var pictureUrl = user.Value<string>("pictureUrl");
if (!string.IsNullOrEmpty(email))
{
context.Identity.AddClaim(new Claim("profile-picture", pictureUrl, ClaimValueTypes.String,
context.Options.ClaimsIssuer));
}
}
}
});
app.Map("/logout", builder =>
{
builder.Run(async context =>
{
// Sign the user out of the authentication middleware (i.e. it will clear the Auth cookie)
await context.Authentication.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
// Redirect the user to the home page after signing out
context.Response.Redirect("/api/Account/LogOut");
});
});
app.Map("/login", builder =>
{
builder.Run(async context =>
{
// Return a challenge to invoke the LinkedIn authentication scheme
await context.Authentication.ChallengeAsync("LinkedIn", properties: new AuthenticationProperties() { RedirectUri = "/api/Account/Create" });
});
});
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
app.UseApplicationInsightsRequestTelemetry();
app.UseApplicationInsightsExceptionTelemetry();
//app.UseJwtBearerAuthentication();
app.UseMvc();
}
As you can see in the end of the file there are two map methods. They are managing login and logout. So can you recomend me how to build my app in right way, or how can create two controller methods, that can do the same things.
Thank you, and sorry for my English