azure-activedirectory-identitymodel-extensions-for-dotnet
azure-activedirectory-identitymodel-extensions-for-dotnet copied to clipboard
[Bug] JwtSecurityTokenHandler.ValidateToken cannot validate JWS if kid is omitted from header
Which version of Microsoft.IdentityModel are you using?
Microsoft.IdentityModel.JsonWebTokens 7.0.2.0
Where is the issue?
- [x ] M.IM.JsonWebTokens
- [ ] M.IM.KeyVaultExtensions
- [ ] M.IM.Logging
- [ ] M.IM.ManagedKeyVaultSecurityKey
- [ ] M.IM.Protocols
- [ ] M.IM.Protocols.OpenIdConnect
- [ ] M.IM.Protocols.SignedHttpRequest
- [ ] M.IM.Protocols.WsFederation
- [ ] M.IM.TestExtensions
- [ ] M.IM.Tokens
- [ ] M.IM.Tokens.Saml
- [ ] M.IM.Validators
- [ ] M.IM.Xml
- [x ] S.IM.Tokens.Jwt
- Other (please describe)
Is this a new or an existing app? The app is in production and I have upgraded to a new version of Microsoft.IdentityModel.*
Repro
var jwtSource = jwt.Replace("Bearer ", "");
var secretBytes = Encoding.ASCII.GetBytes(secret);
// Validate
var tokenHandler = new JwtSecurityTokenHandler();
var validationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
ValidateAudience = false,
ValidateIssuer = false,
IssuerSigningKey = new Microsoft.IdentityModel.Tokens.SymmetricSecurityKey(secretBytes)
};
tokenHandler.ValidateToken(jwtSource, validationParameters, out Microsoft.IdentityModel.Tokens.SecurityToken validatedToken);
Expected behavior I have a JWS that does not specify kid in the header coming from another system. The key is a shared secret (see example code) and is specified in the TokenValidationParameters. The JwtSecurityTokenHandler.ValidateToken method should succeed
Actual behavior Microsoft.IdentityModel.Tokens.SecurityTokenSignatureKeyNotFoundException HResult=0x80131500 Message=IDX10503: Signature validation failed. Token does not have a kid. Keys tried: '[PII of type 'System.Text.StringBuilder' is hidden. For more details, see https://aka.ms/IdentityModel/PII.]'. Number of keys in TokenValidationParameters: '1'. Number of keys in Configuration: '0'. Exceptions caught: '[PII of type 'System.Text.StringBuilder' is hidden. For more details, see https://aka.ms/IdentityModel/PII.]'. token: '[PII of type 'System.IdentityModel.Tokens.Jwt.JwtSecurityToken' is hidden. For more details, see https://aka.ms/IdentityModel/PII.]'. See https://aka.ms/IDX10503 for details. Source=System.IdentityModel.Tokens.Jwt StackTrace: at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateSignature(String token, JwtSecurityToken jwtToken, TokenValidationParameters validationParameters, BaseConfiguration configuration) at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateSignatureAndIssuerSecurityKey(String token, JwtSecurityToken jwtToken, TokenValidationParameters validationParameters, BaseConfiguration configuration) at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateJWS(String token, TokenValidationParameters validationParameters, BaseConfiguration currentConfiguration, SecurityToken& signatureValidatedToken, ExceptionDispatchInfo& exceptionThrown) --- End of stack trace from previous location --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateToken(String token, JwtSecurityToken outerToken, TokenValidationParameters validationParameters, SecurityToken& signatureValidatedToken) at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateToken(String token, TokenValidationParameters validationParameters, SecurityToken& validatedToken)
Possible solution
Additional context / logs / screenshots / links to code This is production code that worked with Microsoft.IdentityModel.JsonWebTokens 5.6.0 Per RFC 7514 kid is optional https://datatracker.ietf.org/doc/html/rfc7515#section-4.1.4
@Donald-Frederick we don't always guarantee that there will not be breaking changes across major versions, however, we will have a look.
This is production code that worked with Microsoft.IdentityModel.JsonWebTokens 5.6.0
@Donald-Frederick Does this code break on v6.3.3 too?
I have run your code on v5.6, v6.33 and v7.0.2 and get the same error each time with my valid token. (What is interesting is that starting in V6, it catches if my token has expired first and in 5.6 does not report expiry, but drops to the error IDX10503 error).
I believe I have an invalid setup with the secret which is patently different from yours and the error is probably valid for me...but it might be good for you to check v6 by you. For there may be something other than the RFC 7514 kid is optional
scenario coming into play. IMHO
SecurityTokenSignatureKeyNotFoundException: IDX10503: Signature validation failed. Token does not have a kid.
@Donald-Frederick @CheetahChrome the reason 6x reports expired first, is because we changed the logic to check for low cost errors before validating the signature, which is the most expensive.
@Donald-Frederick we don't always guarantee that there will not be breaking changes across major versions, however, we will have a look.
We also ran into this issue when upgrading from Microsoft.IdentityModel.* 6.27 to 6.35. I tried going up version by version and this error started at 6.31 to be specific.
The jwt header we receive looks like this.
{ "alg": "HS512", "typ": "JWT" }.
After some investigation I found that the issue was actually that our secret key was too short, 40 bytes instead of 64 bytes. With 6.30 and below that was not "enforced" and tokenHandler.ValidateToken accepted the shorter key and validated the jwt correctly. Starting from 6.31 you will get the "IDX10503: Signature validation failed. Token does not have a kid." error if your secret is shorter than the expected (64 bytes in my case with HS512).
I could repro the issue with the code posted by @Donald-Frederick if using a key that was too small for the given algorithm. Just adding padding makes it run on 6.35.
if (secretBytes.Length < 64)
{
Array.Resize(ref secretBytes, 64);
}
var issuerSigningKey = new SymmetricSecurityKey(secretBytes);
I think padding the key to its expected size is correct, but would be interesting to know why it started breaking on 6.31 for smaller keys.