IDTokenValidator rejects alg=HS256 kid=xxx JWT with "Signed JWT rejected: No matching key(s) found"
Dear support,
Apologies for the second issue I'm opening ;) But I'm facing with the following issue:
I'm doing JWS HMAC ID token validation using clientSecret. Here is a code block I'm executing:
private IDTokenClaimsSet validateIdToken(String idToken, String nonce){
IDTokenValidator idTokenValidator = new IDTokenValidator(new Issuer(getRedirectUrl()), new ClientID(getClientId()), JWSAlgorithm.HS256, new Secret
(getClientSecret()));
try {
JWT idTokenJWT = JWTParser.parse(idToken);
IDTokenClaimsSet idTokenClaimsSet = idTokenValidator.validate(idTokenJWT, new Nonce(nonce));
return idTokenClaimsSet;
} catch (ParseException | JOSEException e) {
throw new ServiceApigeeException("Something wrong with JWT token parsing.");
} catch (BadJOSEException e) {
throw new IdTokenInvalidException("Id token is invalid!");
}
}
And when I invoke "validate" I get the following exception in "com.nimbusds.jwt.proc.DefaultJWTProcessor" -> "Signed JWT rejected: No matching key(s) found" Line #326
I followed this article to perform ID token validation -> http://connect2id.com/blog/how-to-validate-an-openid-connect-id-token
and I'm using that constructor:
ID tokens with HMAC using the client_secret as a key use the alternative constructor: new IDTokenValidator(iss, clientID, jwsAlg, clientSecret);
Any clues what's wrong ? Maybe I have to use some another constructor ? Or ?
Thanks, Dzmitry.
Comments (22)
-
Account Deactivated reporter -
Hi there,
The constructor should indeed be
IDTokenValidator(Issuer expectedIssuer, ClientID clientID, com.nimbusds.jose.JWSAlgorithm expectedJWSAlg, Secret clientSecret)
I'll try to find what exactly the error message could mean.
-
PS: Could paste the header of the ID token? That is, the first BASE64URL segment up to the first dot (.). I want to make sure that the ID token you're getting is indeed secured with "HS256" and not with some other alg.
-
Hi Dzmitry,
The error message that you're getting is indeed symptomatic of trying to do HS256 validation where an RSxxx alg (e.g. RS256) is expected (that requires an RSA public key of the IdP).
Just added a test for this to illustrate: see commit ddbd86f
-
Account Deactivated reporter Hi @vdzhuvinov, @c2id-support
I have the following JWT header:
{ "typ": "JWT", "alg": "HS256", "kid": "KzQq5It4qAlgBMx3GS4m4MrHZnOTKXXh" }
-
Right, so the expected alg is correct.
To drill down I suggest validating the HMAC directly like this:
http://connect2id.com/products/nimbus-jose-jwt/examples/jwt-with-hmac
SignedJWT idTokenJWT = SignedJWT.parse(idToken); JWSVerifier verifier = new MACVerifier(/** secret **/); assertTrue(idTokenJWT.verify(verifier));
-
Here is a test that shows ID token validation with HS256:
If the client secret is incorrect then you should get the following exception: "Signed JWT rejected: Invalid signature"
if you're getting "Signed JWT rejected: No matching key(s) found" this either means that the ID token is RS256 signed, or a constructor for a public RSA key (instead of client secret) was used.
Let us know how the above test works.
Cheers,
-
Account Deactivated reporter Hi @c2id-support ,
I've written the following test:
public void testApp() { String idToken = "***MY_ID_TOKEN***"; SignedJWT idTokenJWT; try { idTokenJWT = SignedJWT.parse(idToken); String secret = "***MY_16_BYTES_SECRET***"; // Secret clientSecret = new Secret(ByteUtils.byteLength(256)); JWSVerifier verifier = new MACVerifier(secret.getBytes()); assertTrue("ID token is invalid", idTokenJWT.verify(verifier)); } catch(ParseException e) { e.printStackTrace(); fail("ParseException exception has occurred" + e.getMessage()); } catch(JOSEException e) { e.printStackTrace(); fail("JOSEException has occurred: " + e.getMessage()); } }
So as a result that test fails with message:
com.nimbusds.jose.KeyLengthException: The secret length must be at least 256 bits at com.nimbusds.jose.crypto.MACProvider.<init>(MACProvider.java:118) at com.nimbusds.jose.crypto.MACVerifier.<init>(MACVerifier.java:145) at com.nimbusds.jose.crypto.MACVerifier.<init>(MACVerifier.java:77) at com.nimbusds.jose.crypto.MACVerifier.<init>(MACVerifier.java:93) at by.test.AppTest.testApp(AppTest.java:45) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:497) at junit.framework.TestCase.runTest(TestCase.java:154) at junit.framework.TestCase.runBare(TestCase.java:127) at junit.framework.TestResult$1.protect(TestResult.java:106) at junit.framework.TestResult.runProtected(TestResult.java:124) at junit.framework.TestResult.run(TestResult.java:109) at junit.framework.TestCase.run(TestCase.java:118)
Can it be the root cause for my issue ? I have only 16 bytes secret long.
-
That's probably it.
The secret key must have the same length as the SHA alg, or be longer.
https://tools.ietf.org/html/rfc7518#section-3.2
I'll check if we can improve the error message for this.
-
The IDTokenVerifiers throws a KeyLengthException with "The secret length must be at least 256 bits" on this, so the exception message is fine.
See commit fdedfade2cfb0886904b15ca20bac62a26202d8f.
-
I don't know what library is used to HMAC the ID tokens, but please let them know that it's not up to the JOSE requirement on the HMAC key length, and security is weakened also with short keys.
-
Account Deactivated reporter Thanks so much @c2id-support, @vdzhuvinov for pointing me out! Quick question. Should I implement secret validation at first before starting with ID token validation based on what we just concluded ?
-
Account Deactivated reporter Also figured out why I have "Signed JWT rejected: No matching key(s) found" exception in DefaultJWTProcessor
So I removed "kid": "KzQq5It4qAlgBMx3GS4m4MrHZnOTKXXh" from JWT header and it now complains on "The secret length must be at least 256 bits" as it should be.
-
What's the intent of having a key ID for the client_secret?
Just added a test to track this case, BTW: 145ef69
-
- changed title to IDTokenValidator rejects alg=HS256 kid=xxx JWT with "Signed JWT rejected: No matching key(s) found"
Updates ticket title
-
Account Deactivated reporter Hi @c2id-support ,
At first thanks so much for the provided guidance. So At the moment I have 2 issues: unexpected Key ID in JWT header and short client secret. So regarding key ID: I'll try to ask my third-party ID token providers regarding it but at the moment I have no idea.
-
There is a way to work around the key ID and ignore it. We'll try to post an example.
As for the key length, this check must be upheld.
-
Account Deactivated reporter @c2id-support ok finally found some info regarding kid in header part. https://tools.ietf.org/html/rfc7515#section-4.1.4
-
Account Deactivated reporter @c2id-support Yes would be great if you can provide me with workaround to ignore this kid in header to proceed with validation. Short client secret issue I'll address to the ID Token signing authors.
-
Account Deactivated reporter @c2id-support Apologies for too many questions. But Have u had a chance to look at my previous comment and give me a hint how to bypass this issue caused by "kid" param in ID token header ?
-
- changed status to resolved
This test shows how to process HSxxx protected ID tokens with a key ID: b2aa75b
The client_secret is converted to a JSON Web Key (JWK), and then put in a JWK credentials set, where it's looked up by the key ID.
-
Account Deactivated reporter @c2id-support thanks so much! It works for me!
- Log in to comment
Actually from my investigations the issue is that jwkSet doesn't contain my secret key.. but at the same time inner LinkedList contains it. Please check out screen I've attached:
That's why I have later the exception I mentioned in description