My context
I'm trying to create a custom User/Role storage for ASP.NET Identity
Background
There are several questions here at SO about getting the user id when using ASP.NET Identity. Most of them resolve around parsing the NameIdentifier
claim.
However, most of them seem to miss an import point. When using OAuth the NameIdentifier
seem to point at the identity that the OAuth provider returned.
This can be observed by setting a break point in the AccountController just after the authentication finished.
My problem
If you look at the UserStore you can see that GetUserIdAsync
will return the Id
of the IdentityUser
object which is your internal id from the database. All good so far.
However, if you look at the UserManager it got the following code:
/// <summary>
/// Returns the User ID claim value if present otherwise returns null.
/// </summary>
/// <param name="principal">The <see cref="T:System.Security.Claims.ClaimsPrincipal" /> instance.</param>
/// <returns>The User ID claim value, or null if the claim is not present.</returns>
/// <remarks>The User ID claim is identified by <see cref="F:System.Security.Claims.ClaimTypes.NameIdentifier" />.</remarks>
public virtual string GetUserId(ClaimsPrincipal principal)
{
if (principal == null)
throw new ArgumentNullException("principal");
return principal.FindFirstValue(this.Options.ClaimsIdentity.UserIdClaimType);
}
.. which looks just fine on the first peak. But if you look at the constant value for UserIdClaimType
it's the same as ClaimTypes.NameIdentifier
. Thus it will fetch the oauth user id.
Code that wont work due to the above problem:
//this returns the oauth id, can't be used to work with the application user
var id = await _userManager.GetUserIdAsync(currentClaimPrincipal);
//this returns null as it internally uses the above line
await user = _userManager.GetUserAsync(currentClaimPrincipal);
The code above will invoke UserStore.FindByIdAsync
with the oath user id as user id. the user storage will therefore try to find the application user by using the incorrect key.
A hack would be to use the oAuth userId as the PK in the local user table, but that can break if two oauth providers return the same id (not unlikely). It also wont work when multiple oauth identifies are associated with the same application user.
My question
Am I doing something wrong? How do user ids relate between the application user store and oauth providers?