I am using a combination of IdentityServer4 and ASP .NET Core Identity to create a federated sign-in page. One of the external providers I am using is Azure Active Directory through the Open ID Connect protocol. I also have integrated EntityFrameworkCore for all of my data storage.
After I scaffolded my initial website with Identity authentication, I add the appropriate services to my Startup.cs
file.
services.AddOidcStateDataFormatterCache();
// Some DI registrations
services.Configure<CookiePolicyOptions>(options =>
{
options.CheckConsentNeeded = context => true;
options.MinimumSameSitePolicy = SameSiteMode.None;
});
services.AddDbContext<MyDbContext>();
services.AddMvc().AddRazorPages(options => /* Some options */);
services.AddIdentityServer(options =>
options.Events.RaiseErrorEvents = true;
options.Events.RaiseFailureEvents = true;
options.Events.RaiseInformationEvents = true;
options.Events.RaiseSuccessEvents = true;
)
.AddConfigurationStore(options => /* Set up DbContext */)
.AddOperationStore(options => /* Set up DbContext */)
.AddAspNetIdentity<MyAppUser>();
services.AddAuthentication().AddOpenIdConnect(options =>
{
// Does not bind itself for mysterious reasons
Configuration.GetSection("OpenIdConect").Bind(options)
});
I decided it would look nicer if I did most of my authentication setup in my appsettings.json
file.
{
"OpenIdConnect": {
"ClientId": "<my_client_id>",
"Authority:" "https://login.microsoft.com/<my_tenant_id>",
"PostLogoutRedirectUri": "http://localhost:5000/MyApp/Account",
"CallbackPath": "/signin-oidc",
"ResponseType": "code id_token",
"Scope": "openid profile email",
"SignInScheme": "idsrv.external",
"AutomaticAuthenticate": "false",
"AutomaticChallenge": "false",
"RequireHttpsMetadata": "true"
}
}
Everything runs and my Open ID Connect login provider appears on the login page automatically. Smashing! Upon trying to use that, I am greeted by an error: Error loading external login information.
Ends up that on the scaffolded Razor page
Areas/Identity/Pages/Account/ExternalLogin.cshtml.cs:72
there is this bit of code:
var info = await _signInManager.GetExternalLoginInfoAsync();
if (info == null)
{
ErrorMessage = "Error loading external login information.";
return RedirectToPage("./Login", new { ReturnUrl = returnUrl });
}
info
always resolved to null. I suspect it is a configuration issue somewhere in my Startup.cs
, or some bit of magic that no documentation bothered to mention.
After reading my brains out, I decided to reread the IdentityServer4 documentation about external identity providers.
This caught my (tired) eye:
Given that this is such a common practise, IdentityServer registers a cookie handler specifically for this external provider workflow. The scheme is represented via the
IdentityServerConstants.ExternalCookieAuthenticationScheme
constant.If you were to use our external cookie handler, then for the SignInScheme [in your OpenIdConnect service setup] you’d assign the value to be the
IdentityServerConstants.ExternalCookieAuthenticationScheme
constant
Well, I think I'm not using their external cookie handler. Pretty sure I'm letting ASP .NET Core Identity do that. I decided to kill this line in my appsettings.json:
"SignInScheme": "idsrv.external"
And behold, I could sign in using my Active Directory credentials. Reading the actual source code of GetExternalLoginInfoAsync
, I saw that they were looking for a very specific cookie, and it wasn't "idsrc.external"
. Leaving it as its default was what I needed.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With