Just trying to understand a problem, that appears in my head to be a bug in the Microsoft System.Security dll, but probably something I am doing incorrectly.
I am trying to custom implement a JWT token. I create the claims and the token:
var claimsIdentity = new ClaimsIdentity(new List<System.Security.Claims.Claim>()
{
new System.Security.Claims.Claim(ClaimTypes.Sid, "1"),
new System.Security.Claims.Claim(ClaimTypes.Role, "1"),
},"Custom");
var securityTokenDescriptor = new SecurityTokenDescriptor()
{
AppliesToAddress = Keys.Core.WebsiteDomain,
TokenIssuerName = Keys.Core.WebsiteDomain,
Subject = claimsIdentity,
SigningCredentials = signingCredentials,
};
var tokenHandler = new JwtSecurityTokenHandler();
var plainToken = tokenHandler.CreateToken(securityTokenDescriptor);
var signedAndEncodedToken = tokenHandler.WriteToken(plainToken);
return signedAndEncodedToken;
I then go to retrieve the token and the User (SID) and Role values:
var roleId = stream.Claims.SingleOrDefault(x => x.Type == ClaimTypes.Role).Value;
var userId = stream.Claims.SingleOrDefault(x => x.Type == ClaimTypes.Sid).Value;
Validate Function:
private static JwtSecurityToken Validate(string signedAndEncodedToken)
{
var tokenHandler = new CustomJwtSecurityTokenHandler();
var plainTextSecurityKey = Keys.Security.TokenSecret;
var signingKey = new InMemorySymmetricSecurityKey(
Encoding.UTF8.GetBytes(plainTextSecurityKey));
var tokenValidationParameters = new TokenValidationParameters()
{
ValidateIssuer = false,
ValidateAudience = false,
IssuerSigningKey = signingKey
};
SecurityToken validatedToken;
tokenHandler.ValidateToken(signedAndEncodedToken, tokenValidationParameters, out validatedToken);
var jwtToken = validatedToken as JwtSecurityToken;
return validatedToken as JwtSecurityToken;
}
Now My UserID (ClaimType.SID) appears to return correctly, but my RoleId (ClaimType.Role) comes back as non existant. If I change x.Type == "role" it works correctly.
On inspection on the Claim.Type SID appears as: http://schemas.xmlsoap.org/ws/2005/05/identity/claims/sid
But Claim.Type Role appears as: Role.
ClaimTypes.Role has the full Schema path.
Is this a bug, or am I missing something?
I realized sometime has passed, but as someone who was surprised by this as well, I did encounter this comment on the JwtSecurityToken.Claims
property:
Claim(s) returned will NOT have the Claim.Type
translated according to JwtSecurityTokenHandler.InboundClaimTypeMap
So if you want to use ClaimTypes
when searching in a decoded token, you can just run it through that dictionary and know that you're not insane or did anything wrong.
Assert.Equal(
"Nicholas Piasecki",
parsedToken
.Claims
.Single(x =>
{
var map = JwtSecurityTokenHandler.DefaultInboundClaimTypeMap;
if (map.TryGetValue(x.Type, out var mapped))
{
return mapped == ClaimTypes.GivenName;
}
return false;
})
.Value);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With