runtime: System.Security.Claims.Claim value type incorrect
The type of System.Security.Claims.Claim.Value is to string which is contrary to the spec:
Claim Value The value portion of a claim representation. A Claim Value can be any JSON value.
This is big problem for us while creating a .NET Core app for a large established ecosystem where JWTs have object claims.
The problem is exacerbated by the fact that now System.IdentityModel.Tokens.Jwt library is dependent on this implementation in the way it deserialises JWTs into ClaimsIdentity and then into ClaimsPrincipal… (e.g. here or here)
About this issue
- Original URL
- State: closed
- Created 8 years ago
- Comments: 25 (18 by maintainers)
As far I understand the correct way of processing a raw JWT into a principal is by executing this:
Here’s an example JWT:
eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzUxMiIsImlzRW5jcnlwdGVkIjoiRmFsc2UiLCJ4NXQiOiI1M0VENjE1NTUwNTlBRDg3QUE4MkNBNTYwRTQ4QkIxMkM1MzdGOUY1IiwidmVyIjoiMi4xIn0.eyJhdWQiOiJIZWxpeC5TZWN1cml0eS5VdGlsIiwiaWF0IjoiMTQ3MjA5NjU1Ny43NDM3NiIsIm5iZiI6IjE0NzIwOTY1NDQuNzU3NTkiLCJDbGFpbVNldHMiOlt7IkNsYWltcyI6eyJzZXJ2ZXJJZCI6IkhlbGl4LkNvbnRhaW5lcnMuRGV2Iiwic2VydmVyVmVyc2lvbiI6ImRldiIsImlzc1g1dCI6IjUzRUQ2MTU1NTA1OUFEODdBQTgyQ0E1NjBFNDhCQjEyQzUzN0Y5RjUifSwiUHJvdmlkZXIiOiJIZWxpeC5Db250YWluZXJzLkRldi52ZGV2IiwiU2NoZW1hIjoiSGVsaXguQ29udGFpbmVyIiwiVmVyc2lvbiI6IlYxIn1dLCJpc3MiOiJIZWxpeC5Db250YWluZXJzLkRldi52ZGV2IiwiZXhwIjoiMTQ3MjA5Nzc0NC43NTg1OSIsInNzaWQiOiJjNmJkNzY3ZjE4YWU0ZTQyOTliMmY4YjJmNzhmODU1NSJ9.W8ARsO3IKMO_CBl5fMkgTEkPmoZZvjaX46-mmVHqT5hQAbQVBmnc18B9VxsSS34YKVE2dBQwZHjhu2ROSOCKeuHOqHjjS_HuSdDLOdi7rJUdpKw1GE-lBqxzUPojAlUvLRlq7KjbwipXd7bJyMk7chVU9r548pmljDAlm7SOqmM-qcZ8X0sgQcDxxZoacJiL9xQpbJPi9CVHC_ms2LJhm6AFcCNTlRZNgAmMvoIBWfjXVsVC92HFgqd_qTpMvudTs216LIfslpJC0WiU4SFWKV2Bt5rGGVVqSe4vXb4W1Si58t8ORcepRnkZ1jkEuKf2VpHTEw0ylwX_BLqnnKdavQDecoded to JSON:
Once raw JWT is loaded into an instance of
JwtSecurityTokenit has the followingPayload:However its
Claimare as follows:The
ClaimSetsclaim is serialised back to string…Now a
JwtSecurityTokenHandlertakes the deserialised JWT and loads it into an instance ofClaimsIdentity:At the end of all of this, the principal has all claims serialised back to
stringwhich is incorrect and extremely inefficientOne of the primary reasons is that we need to serialize an identity into a cookie. We can’t serialize and deserialize arbitrary types. There are also several other operations we do like merging multiple ClaimsPrincipals into a single principal.
@RussKie The last two sentences were related to asp.net users. For users of IdentityModel, we have extensibility that allows you to create your own custom ClaimsIdentity returned from ValidateToken. Both JwtSecurityTokenHandler.CreateClaimsIdentity and TokenValidationParameters.CreateClaimsIdentity are virtual and between the two, you can have a custom ClaimsIdentity OR CustomClaims. We do not have a delegate for CreateClaimsIdentity, as we do for many other overloads. Deriving is necessary.
I am the only one seeing the problem with this? 😱
As an end-consumer app developer I should not be locked in dealing with strings, it is just too impractical. I should be dealing with whatever objects fit my business requirements. Ultimately in the code the developers don’t deal with JWTs (it is a mere transport object), they deal the identities.
To put this in a context. Previously HTTP context would expose the user as
IPrincipal(https://github.com/Microsoft/referencesource/blob/master/System.Web/HttpContext.cs#L1237). Now in OWIN/.NETCore HttpContext it is no longer the case, it isClaimsPrincipal. This means I can’t substitute it with a custom principal. Because I can’t put my custom principal I can’t expose my custom identity as it is now ofClaimsIdentitytype. And the ClaimsIdentity only provides me with strings…For example:
I can no longer do anything like this in OwinContext / .NETCore HttpContext…
I don’t agree with the current implementation of ClaimsIdentity - it is too rigid. Either it has to support more than just string claims or there has to be a mechanism for me to inject my custom principal/identity which support other than string claims. So far I haven’t found any ways to achieve this cleanly. 😢