3

This is a simplified test for JwtSecurityTokenHandler 4.0.0 in Linqpad. The code works well with JwtSecurityTokenHandler 3.0.2, the token is generated and validated. In 4.0.0, after the necessary changes, I keep getting SecurityTokenSignatureKeyNotFoundException: IDX10500: Signature validation failed. Unable to resolve SecurityKeyIdentifier. Obviously something has changed or I am doing something wrong and the new version is more strict. Any suggestions?

string jwtIssuer = "issuer";
string jwtAudience = "audience";

X509Store store = new X509Store(StoreName.My,  StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadOnly);
X509Certificate2 cert = store.Certificates.OfType<X509Certificate2>().FirstOrDefault( c => c.SubjectName.Name.Equals("CN=DEV_CERT", StringComparison.OrdinalIgnoreCase));
store.Close();
// Token generation and signing
X509SigningCredentials signingCredentials = new X509SigningCredentials(cert);
JwtSecurityTokenHandler jwtHandler = new JwtSecurityTokenHandler();
IList<System.Security.Claims.Claim> payloadClaims = new List<System.Security.Claims.Claim>() { 
    new System.Security.Claims.Claim(System.Security.Claims.ClaimTypes.Name , "name"), 
};

#if JWT302
    Lifetime lifetime = new Lifetime(DateTime.UtcNow, DateTime.UtcNow.AddSeconds(24*60*60));
    JwtSecurityToken jwt = new JwtSecurityToken( jwtIssuer, jwtAudience, payloadClaims,  lifetime, signingCredentials);
#else
    JwtSecurityToken jwt = new JwtSecurityToken( jwtIssuer, jwtAudience, payloadClaims, DateTime.UtcNow, DateTime.UtcNow.AddSeconds(24*60*60), signingCredentials);
#endif

string token = jwtHandler.WriteToken(jwt); 

// Token validation
var signingToken = new RsaSecurityToken((RSACryptoServiceProvider)cert.PublicKey.Key);

JwtSecurityTokenHandler jwtHandler2 = new JwtSecurityTokenHandler();

#if JWT302
TokenValidationParameters vp = new TokenValidationParameters() {  
                                        AllowedAudience = jwtAudience, 
                                        ValidIssuer = jwtIssuer,
                                        ValidateIssuer = true
                                        ,SigningToken = signingToken 
                                        };

    var principal  = jwtHandler2.ValidateToken(token, vp);
#else
TokenValidationParameters vp = new TokenValidationParameters() { 
                                        ValidAudience = jwtAudience, 
                                        ValidIssuer = jwtIssuer,
                                        ValidateIssuer = true
                                        ,IssuerSigningToken = signingToken 
                                        };

    SecurityToken validatedToken;

    var principal  = jwtHandler2.ValidateToken(token, vp, out validatedToken);
#endif

2 Answers2

6

This exception is thrown if:

  1. The jwt has a 'kid'
  2. The runtime was unable to match any of the SigningTokens.

While we investigate the issue, you can use the delegate TokenValidationParameters.IssuerSigningKeyResolver to directly return the signing key to use when checking the signature.

To achieve this set: TokenValidationParameters.IssuerSigningkeyResolver to a function that will return the same key that you set above in TokenValidationParameters.SigningToken. The purpose of this delegate is to instruct the runtime to ignore any 'matching' semantics and just try the key.

If the signature validation still fails, it may be a key issue.

If the signature validation doesn't fail, the runtime may need a fix.

If you can provide us with a jwt signed with that public key, that would help us make a fix.

thanks for giving us a try, sorry for the hassle.

Brent Schmaltz
  • 1,151
  • 6
  • 7
  • 1
    In reviewing, the new matching algorithms will not validate the signature if a 'kid' exists in the jwt. Since you signed with a X509, a x5t will be present in the jwt. This will not match the RSA key. Instead try adding an X509SecurityKey or X509SecurityToken. – Brent Schmaltz Sep 02 '14 at 14:22
  • I tried adding a kid to no avail.. will repeat the test. I can provide the certificates that I am using, tokens and the code (either as a Linqpad script or a Console App just let me know). You can email me directly to rmbrunet at gmail. – Roberto Martinez-Brunet Sep 02 '14 at 15:08
  • This is the full exception after adding a kid – Roberto Martinez-Brunet Sep 02 '14 at 15:11
  • SecurityTokenSignatureKeyNotFoundException: IDX10500: Signature validation failed. Unable to resolve SecurityKeyIdentifier: 'SecurityKeyIdentifier ( IsReadOnly = False, Count = 2, Clause[0] = X509ThumbprintKeyIdentifierClause(Hash = 0x6A780AF6E7838FF74783ACA9487DDB6433A98DD2), Clause[1] = System.IdentityModel.Tokens.NamedKeySecurityKeyIdentifierClause ) ', token: '{"typ":"JWT","alg":"RS256","kid":"6A780AF6E7838FF74783ACA9487DDB6433A98DD2","x5t":"angK9ueDj_dHg6ypSH3bZDOpjdI"}.{"unique_name":"name","iss":"issuer","aud":"audience","exp":1409757052,"nbf":1409670652} – Roberto Martinez-Brunet Sep 02 '14 at 15:14
  • 1
    Using an X509SecurityKey instead of a RsaSecurityToken (as you suggested) the Validation passes. – Roberto Martinez-Brunet Sep 02 '14 at 16:36
  • Thank you!!! I have similar problems with trying to use Live Id, your answer helped me with this – Maxim Alexeyev Mar 20 '15 at 04:25
  • When I was looking at the legacy endpoints for Token validation, I had to implement the callback and lowercase the thumbprint in comparisons. Full example of Google token verification fix here, lines 100-112: https://github.com/googleplus/gplus-verifytoken-csharp – class Jun 20 '15 at 02:11
2

Sorry you're experiencing issues. We will get some more eyes on the above to see what might be wrong. In the meanwhile, I suggest taking a look to https://github.com/AzureADSamples/WebAPI-ManuallyValidateJwt-DotNet and in particular global.asax.cs - that's the sample where we feature raw use of the JWT handler. HTH V.

vibronet
  • 7,364
  • 2
  • 19
  • 21
  • I opened up this issue: https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/issues/192 we will have a look. – Brent Schmaltz Jun 30 '15 at 15:59