I am using multiple authentication schemes. Here is my Startup.cs code -
public void ConfigureServices(IServiceCollection services)
{
//code
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = "Default";
options.DefaultSignInScheme = "Default";
options.DefaultChallengeScheme = "O365OpenId";
})
.AddCookie("Default",options =>
{
options.LoginPath = "/";
options.LogoutPath = "/Logout";
options.Cookie.Name = "ip" + guid.ToString();
options.AccessDeniedPath = "/Auth/Denied";
})
.AddCookie("External", options =>
{
options.LoginPath = "/Auth/External";
options.LogoutPath = "/Logout";
options.Cookie.Name = "ip" + guid.ToString();
options.AccessDeniedPath = "/Auth/Denied";
})
.AddOAuth("O365OpenId", options =>
{
//options.Authority = "given";
options.ClientId = "given";
options.ClientSecret = "given";
options.CallbackPath = "/auth/callback";
options.AuthorizationEndpoint = "https://login.microsoftonline.com/common/oauth2/v2.0/authorize";
options.AuthorizationEndpoint += "?prompt=select_account";
options.TokenEndpoint = "https://login.microsoftonline.com/common/oauth2/v2.0/token";
options.UserInformationEndpoint = "https://graph.microsoft.com/oidc/userinfo";
options.AccessDeniedPath = "/Auth/Denied";
options.Scope.Add("openid");
options.Scope.Add("email");
//options.Scope.Add("profile");
//options.Scope.Add("offline_access");
//options.Scope.Add("user.read");
//options.Scope.Add("calendars.read");
options.SaveTokens = false;
//options.ClaimActions.MapJsonKey(ClaimTypes.NameIdentifier, "id");
//options.ClaimActions.MapJsonKey(ClaimTypes.GivenName, "given_name");
//options.ClaimActions.MapJsonKey(ClaimTypes.Surname, "family_name");
//options.ClaimActions.MapJsonKey(ClaimTypes.Name, "name");
options.ClaimActions.MapJsonKey(ClaimTypes.Email, "email");
//options.ClaimActions.MapJsonKey(ClaimTypes., "picture");
options.Events = new OAuthEvents
{
OnCreatingTicket = async context =>
{
if (context.AccessToken is { })
{
context.Identity?.AddClaim(new Claim("access_token", context.AccessToken));
}
var request = new HttpRequestMessage(HttpMethod.Get, context.Options.UserInformationEndpoint);
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", context.AccessToken);
var response = await context.Backchannel.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, context.HttpContext.RequestAborted);
response.EnsureSuccessStatusCode();
var json = JsonDocument.Parse(await response.Content.ReadAsStringAsync());
context.RunClaimActions(json.RootElement);
};
});
services.AddAuthorization(options =>
{
options.AddPolicy("Admin", policy =>
{
policy.AuthenticationSchemes.Add(CookieAuthenticationDefaults.AuthenticationScheme);
policy.RequireAuthenticatedUser();
policy.RequireRole("Admin");
});
options.AddPolicy("Regular&Admin", policy =>
{
policy.AuthenticationSchemes.Add(CookieAuthenticationDefaults.AuthenticationScheme);
policy.RequireAuthenticatedUser();
policy.RequireRole("Regular");
});
options.AddPolicy("External", policy =>
{
policy.AuthenticationSchemes.Add("External");
policy.RequireAuthenticatedUser();
policy.RequireRole("External");
});
});
}
When I sign in user using the "Default" scheme, I find that the HttpContext.User.Identity.IsAuthenticated is true after HttpContext.SignInAsync("schema-name", claimsPrincipal); method call. Here is the code for signing in -
public async Task<IActionResult> Success(string returnUrl)
{
// code
var claimIdentity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);
var claimsPrincipal = new ClaimsPrincipal(claimIdentity);
await HttpContext.SignInAsync("Default",claimsPrincipal);
// more code
}
But When I sign in user using "External" scheme, HttpContext.User.Identity.IsAuthenticated is false after HttpContext.SignInAsync("schema-name", claimsPrincipal); call. Here is the code for signing in -
public async Task<IActionResult> External([FromQuery] string ReturnUrl, LoginOTP loginOTP, string email)
{
//code
var claimIdentity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);
var claimsPrincipal = new ClaimsPrincipal(claimIdentity);
await HttpContext.SignInAsync("External", claimsPrincipal);
//code
}
I cannot understand what I am doing wrong. Why is the IsAuthenticated returning false? Please help. Thank you.
you have 3 authentication schemes
when referring to one of these schemes you should use the names that you have created.
now the issue is, that you're creating a ClaimeIdentity with one scheme but you signing the user with a different scheme.
for the external method it should be like this:
now the claims principal will be associated with the "External" scheme and the user will be authenticated.