7
votes

I'm using IdentityServer4 as an OIDC provider and ASP.NET Core 2.0.

I have gone through several posts to ensure that the claims issued by IdentityServer end up in the ClaimsPrincipal (ie Auth Cookie), and have managed to get this working with ClaimsAction filtering.

However my question is this ... When running IdentityServer with the ASP.NET Identity (and EF backing store), how do the ASP.NET Identity properties get mapped to the claims returned by IDS4. By default, IDS4 returns claims like ...

  • "sub" : from IdentityUser.Id
  • "name" : from IdentityUser.UserName
  • "preferred_username" : from IdentityUser.UserName
  • "email" : from IdentityUser.Email
  • "email_verified" : from IdentityUser.EmailConfirmed

The reason I ask this, is that I would like to map

  • "given_name": from IdentityUser.FirstName (an extended property)
  • "family_name": from IdentityUser.LastName (an extended property)

as IDS4 does not appear to do this by default when requesting the PROFILE scope.

In addition, I would like to ask what would be best-practice for storing user properties. When using the ASP.NET Identity DB, two tables are created ...

  • AspNetUsers
  • AspNetUserClaims

So would it be best practice to add additional user properties as ...

  1. Properties on the IdentityUser (which get added to AspNetUsers as new fields) OR ...
  2. Additional Claims in AspNetUserClaims (these can be added at registration or login time using UserManager.AddClaimAsync())
1
I have the same question. From what I’ve seen, if I add the given name as a claim, IdentiyServer automatically sends it in the id token. That makes me think that the claims option is better. Apart from that, registering data as claims has an advantage when not all users have value for that property.Mario Gomez

1 Answers

5
votes

How to map user-properties to claims

As you answered yourself, the extended property should be mapped programmatically.

  • If you want to add columns to the AspNetUsers table, you extend the IdentityUser class (e.g. public class MyApplicationUser : IdentityUser), then add your custom properties (eg FirstName). This essentially changes the model. To ensure that EF writes your model changes to the DB table, you need to extend the IdentityDbContext class with your new MyApplicationUser class.
  • If you want custom claims for the user (e.g. hair_color) to be added to the AspNetUserClaims table, you need to call userManager.AddClaimAsync(). You could do this during the registration process or login process with data from the form, or from claims received from external auth providers such as Google, Facebook, Twitter etc.

But, as you can read in my answer to your additional question, I think you should not map them, but make them claims right away.

Where to store user-properties

I found your additional question more interesting: what properties to add to AspNetUsers and when to AspNetUserClaims?

Edit: Updated answer

After some discussion, I would probably say, that the main consideration would be:

  • Properties for which ASP.NET Identity is your primary source of user data should be strongly typed database columns (typically in AspNetUsers) and propagated to claims (when necessary) when creating the principal.
  • Properties imported and updated from another source can be propagated to claims in the DB (AspNetUsersClaims) right away.

Example:

  • if hair_color is a property entered and changed by the user in this identity-interface, you store it in a strongly typed database column.
  • if hair_color is a property maintained in another application and updated from there, I would store it as a record in the claims-table.

In the case I worked on when writing the original answer (below), the user data to be shared was updated indirectly from another (primary) source, but for the authentication details ASP.NET Identity was the primary source. So it resulted in the same distribution, but for a different reason.

Original answer

As I understand it, the rule of thumb is:

  • data that is (only) meant for sharing with other applications (user-info), should be protected identity resources, hence claims in AspNetUsersClaims.
  • data that is functionally used for authentication (authentication-info) should be part of the user (AspNetUsers), so data for: identification, login, restore, 2-fact, etc. (e.g. username, password, email, phone)

Examples:

  • if you want to add a DateOfBirth I would add it to AspNetUsersClaims (unless you intend to use it for authentication/login somehow)
  • if you want to store account/login-related data like accountExpiresDate or CreatedFromIP you add it to AspNetUsers (and extend IdentityUser)

So if you use a UserClaimsPrincipalFactory to add a user-property to your user-claims, you may just be adding the property to the wrong table!

TLDR

I actually found your question, while wondering about this myself, yet again. I started using the above rule of thumb, but the question kept coming up, because a lot of examples don't follow this rule. E.g. Microsoft has an example suggesting to add Name and DOB, which seems to contradict this. However, OpenID already defines these properties (a.o.) as standard claims in the optional profile scope: birthdate, name, family_name, given_name, middle_name, nickname, preferred_username.