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.