Search code examples
c#facebookasp.net-coreasp.net-core-identity

Handle claims with external login provider


I'm a longtime .NET Framework/WebForms developer, and am moving to Core (2.1) for a new project. I've got the foundation pieces stood-up, with a VS solution housing a DAL project and a web app project (in MVC). I'm using Core Identity, and have added-in the default identity scaffold files. It's all fine, with Facebook registration/authentication working. As of yet I don't entirely understand how the authentication scheme works, but I'm beginning to piece it together.

One thing that's getting to me -- and something for which I can't seem to find any clear, straightforward documentation, is how to handle claims data that comes across from Facebook. I get that everything you request, in the set-up for the AddAuthentication() method, gets saved to the client cookie, and you can retrieve it that way. But what I want to do is go ahead and have that information persisted to the IdentityClaims table.

In Startup.cs, I've got AddAuthentication() set-up like this:

services.AddAuthentication().AddFacebook(options =>
{
    options.AppId = "XXXXXXXXXX";
    options.AppSecret = "XXXXXXXXXX";
    options.SaveTokens = true;
    options.Scope.Add("public_profile");
    options.Scope.Add("email");
    options.Fields.Add("name");
    options.ClaimActions.MapJsonKey(ClaimTypes.Name, "name");
});

I honestly don't entirely know that I've got that set-up correctly, to ask for the "name" claim to be included in the request... But even if it was, I gotta admit that I really don't know what to do with it, afterwords.

My guess has been that something has to happen in the OnPostConfirmationAsync() method of the ExternalLogin.cshtml.cs file, in the \Identity\Pages\Account folder. Probably something like:

UserManager.AddClaimAsync(user, ...something...);

But I really don't know, and it sure seems like there must be a better way. Like: is there a way to configure options such that invocation of the UserManager.CreateAsync() method automatically stores claims, as well?

These are all very elementary questions, and I'm frustrated with myself for not being able to see it clearly. All I need is a good example to work from, and I'm sure I'll get it. Everything else, so far, has seemed pretty basic.


Solution

  • Surprised at how quickly after posting this I found an answer to my own question, and also how elementary it really is.

    I'll be honest and say that I didn't really and completely understand what was going-on with all the various option settings, with respect to the external provider login setup (in this case, Facebook).

    As it turns-out, it's not necessary to specifically call for the "name" field to be added (it's part of the "public_profile" scope). It's also not necessarily advantageous to map the claim type to a more readable name, at that level, either. I think that would only be necessary if you're trying to get the external login to work with some sort of existing functionality, which is expecting a particular value, and you can't change the code, there.

    At any rate, if you're using an external provider, once you get the response, and have an instances of SignInManager and UserManager, you can simply:

    var info = [SignInManager instance].GetExternalLoginInfoAsync();
    [UserManager instance].AddClaimsAsync([IdentityUser instance], info.Principal.Claims);
    

    That'll throw every single claim gotten back from the external provider into the user claims table. I happen to be doing something slightly more complicated than that, which involved looping through the claims, to get the ones desired. This is fairly simple to do, once you realize (as I now have) that the built-in System.Security.Claims.ClaimTypes Type contains mappings to the fully-qualified schema names for all common claim types. So just sort through the ones you want, and add them as you see fit. Simple.