ASP.NET Identity: Update external claims after authorization
Asked Answered
N

1

15

I am using ASP.NET Identity with several external login providers and I need to handle the following scenario:

1) A user logs in using an external service (let's say it is Facebook), application grabs some info from Facebook (first and last name, email, date of birth, etc...) Claims containing this info are added to the identity.

2) I need to store this info in the application Db, for the following scenarios:

  • Admin browses the list of registered users

  • Email subscription service will use first and last names

  • ...

The question is what about if user will update his/her Facebook profile (e.g., change email address) - in this case I need to update information in my Db too (I store external claims in AspNetUserClaims table). Actually I need to update it every time an external user is authenticated.

Here's the code of how it is saved for the first time:

Extended Claim class:

public class ApplicationUserClaim : IdentityUserClaim<Guid>
{
    public string Issuer { get; set; }
    public string ClaimValueType { get; set; }
}

Startup:

var facebookOptions = new FacebookAuthenticationOptions {
    AppId = "...",
    AppSecret = "...",
    Provider = new FacebookAuthenticationProvider {
        OnAuthenticated = (context) => {
            context.Identity.AddClaims(new[] {
                new Claim("LastName", context.User["last_name"].ToString(), ClaimValueTypes.String, "Facebook"),
                new Claim("FirstName", context.User["first_name"].ToString(), ClaimValueTypes.String, "Facebook"),
                //...Other claims
            });
        }
    }
};

facebookOptions.Scope.Add("email");
facebookOptions.Scope.Add("user_birthday");

app.UseFacebookAuthentication(facebookOptions);

AuthController

External Login callback:

public ActionResult ExternalLogin(string returnUrl)
{
    var loginInfo = authenticationManager.GetExternalLoginInfo();

    //No user found - this is the first login with an external service
    //Asking to confirm an external account
    if(signInStatus == SignInStatus.Failure)
        return View("ExternalLoginConfirmation", new ExternalLoginConfirmationViewModel { ... });    
}

Creating an user after external login confirmation (omitting other code):

public ActionResult ExternalLoginConfirmation(ExternalLoginConfirmationViewModel loginConfirmationViewModel)
{
    var loginInfo = authenticationManager.GetExternalLoginInfo();

    var user = new ApplicationUser();

    user.Logins.Add(new RegisteredUserLogin {
        LoginProvider = loginInfo.Login.LoginProvider,
        ProviderKey = loginInfo.Login.ProviderKey
    });

    //Converting Claims added in OnAuthenticated callback to ApplicationClaim objects to store them in Db
    foreach(var userInfoClaim in loginInfo.GetUserInfoClaims())                        
        user.Claims.Add(ClaimsHelper.ToUserClaimObject(userInfoClaim));

    userManager.Create(user);
}

This works fine, but I'm stuck with updating incoming claim values after a Facebook user comes back. What is the true way to handle such a situation? Thx.

Nalda answered 25/2, 2015 at 13:38 Comment(2)
Did you ever get this sorted? I'm wondering the same myself...Preparation
I'm in the same situation myself. When the user returns and you log them in with SignInManager.ExternalLoginSignInAsync() it populates the identity with the claims you saved to the local account which makes sense, but I'm not sure what the correct way to update those claims is on subsequent logins.Piroshki
E
1

This is a bit costy but the easiest answer:

You can just check the same information whenever the user logs in and update them if changed. Since you have no direct connection to Facebook, you can never know when the users change their information.

This should result be an OK approach unless you have thousands of logins to your system in a minute.

Exfoliate answered 22/10, 2018 at 12:9 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.