I have a web application that allow users to login and register using local authentication (with JWT Authentication scheme), and also allow users to login in their azure active directory account (using OpenIdConnect Scheme). I'm treating the logging with azure active directory as an external login, however, I keep getting null response when I'm trying to get the GetExternalLoginInfoAsync()
Below is my setup:
services.AddAuthentication(options =>
{
options.DefaultScheme = "JWT_OR_COOKIE";
options.DefaultChallengeScheme = "JWT_OR_COOKIE";
})
.AddCookie(CookieAuthenticationDefaults.AuthenticationScheme)
// for azure active directory
.AddOpenIdConnect(OpenIdConnectDefaults.AuthenticationScheme, options =>
{
options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.Authority = config["authority"];
options.ClientId = config["clientId"];
options.ClientSecret = config["clientSecret"];
options.ResponseType = "code";
options.SaveTokens = true;
})
// for local login
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(config["TokenKey"])),
ValidateIssuer = false,
ValidateAudience = false,
NameClaimType = "name",
RoleClaimType = "role"
};
options.RequireHttpsMetadata = env.IsProduction();
})
.AddPolicyScheme("JWT_OR_COOKIE", "JWT_OR_COOKIE", options =>
{
// runs on each request
options.ForwardDefaultSelector = context =>
{
// filter by auth type
string authorization = context.Request.Headers[HeaderNames.Authorization];
if (!string.IsNullOrEmpty(authorization) && authorization.StartsWith("Bearer "))
return JwtBearerDefaults.AuthenticationScheme;
// otherwise always check for cookie auth
return OpenIdConnectDefaults.AuthenticationScheme;
};
});
services.AddAuthorization(options =>
{
options.AddPolicy("RequireAdminRole", policy => policy.RequireRole("Admin"));
});
My controller:
[HttpGet("login")]
[AllowAnonymous]
public async Task<IActionResult> ExternalLogin([FromQuery] string returnUrl)
{
var scheme = OpenIdConnectDefaults.AuthenticationScheme;
var redirectUrl = Url.Action("ExternalLoginCallback", "Account", new { ReturnUrl = returnUrl });
return Challenge(new AuthenticationProperties
{
RedirectUri = redirectUrl
}, scheme);
}
[HttpGet]
[AllowAnonymous]
public async Task<IActionResult> ExternalLoginCallback(string returnUrl)
{
var acccessToken = await HttpContext.GetTokenAsync("access_token"); // <== this works
var info = await _signInManager.GetExternalLoginInfoAsync(); // <=== this is null, and I don't know what I did wrong in here !!!
var result = await _signInManager.ExternalLoginSignInAsync(info.LoginProvider, info.ProviderKey, isPersistent: false);
if (result.Succeeded)
{
// update any authentication process
await _signInManager.UpdateExternalAuthenticationTokensAsync(info);
return LocalRedirect(returnUrl);
}
else
{
// do not have account yet
return Ok();
}
}