1

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?

jgauffin
  • 99,844
  • 45
  • 235
  • 372

1 Answers1

0

You shouldn't be calling GetUserId with the claims principal from an OAuth provider. The only ClaimsPrincipal that should be used with that is one generated via the ClaimsPrincipalUserFactory that identity uses. Associating OAuth with the local user is usually done via the AddLogin method which links the OAuth id to the local user id.

Hao Kung
  • 28,040
  • 6
  • 84
  • 93