Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AspNet Core Identity GetExternalLoginInfoAsync Always Null

Tags:

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.

like image 705
Daniel L. Avatar asked Apr 19 '19 05:04

Daniel L.


1 Answers

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.

like image 134
Daniel L. Avatar answered Oct 11 '22 21:10

Daniel L.