-
Notifications
You must be signed in to change notification settings - Fork 6.2k
Description
Describe the bug
In Spring Security 7, a NimbusJwtEncoder constructed by private NimbusJwtEncoder(JWK jwk) produces Jwt objects with incorrent "typ" parameter values in headers. The "typ" header parameter should declare the media type of the complete JWT and the value should be "JWT" in most cases, as is defined in RFC 7519. However, the value emitted by NimbusJwtEncoder is acutally the type of the signing JWK, i.e. the "kty" value defined in RFC 7517, whose common values include "RSA", "EC", "oct", etc.
Such an incorrect "typ" value is rejected by JwtTypeValidator.jwt(), which is employed by NimbusJwtDeocder by default in Spring Security 7, causing a JWT verification error.
This bug was introduced in Line 139 below, where jwk.getKeyType() was passed to JwsHeader.Builder::type(String type):
Lines 131 to 139 in 676b44e
| private NimbusJwtEncoder(JWK jwk) { | |
| Assert.notNull(jwk, "jwk cannot be null"); | |
| this.jwkSource = new ImmutableJWKSet<>(new JWKSet(jwk)); | |
| JwsAlgorithm algorithm = SignatureAlgorithm.from(jwk.getAlgorithm().getName()); | |
| if (algorithm == null) { | |
| algorithm = MacAlgorithm.from(jwk.getAlgorithm().getName()); | |
| } | |
| Assert.notNull(algorithm, "Failed to derive supported algorithm from " + jwk.getAlgorithm()); | |
| JwsHeader.Builder builder = JwsHeader.with(algorithm).type(jwk.getKeyType().getValue()).keyId(jwk.getKeyID()); |
To Reproduce
-
Create a
NimbusJwtEncoderinstance usingSecretKeyJwtEncoderBuilder(You may also useRsaKeyPairJwtEncoderBuilderorEcKeyPairJwtEncoderBuilder, as long as the private constructor is invoked):SecretKey secretKey = KeyGenerator.getInstance("HmacSHA256").generateKey(); NimbusJwtEncoder jwtEncoder = NimbusJwtEncoder.withSecretkey(secretKey).build();
-
Encode a JWT with the
NimbusJwtEncoderinstance:JwtClaimsSet claims = TestJwtClaimsSets.jwtClaimsSet().build(); Jwt jwt = jwtEncoder.encode(JwtEncoderParamaters.from(claims));
-
Print out the
"typ"parameter value, and you'll seeoct—— the"kty"of a HS256 JWK.System.out.println(jwt.getHeaders().get(JoseHeaderNames.TYP)); // It prints: oct
Expected behavior
The expected value of the "typ" header parameter is often "JWT". If RFC 9068 is anticipated it may be "at+jwt".
Sample
I was surprised by the fact that this bug hasn't been caught by existing tests, so I created a symmetric test NimbusJwtEncoderDecoderTests.java where a JWT encoded with NimbusJwtEncoder is then decoded with NimbusJwtDecoder. With a JwtTypeValidator included in JwtValidators.createDefault(), NimbusJwtDecoder throws a JwtValidationException, saying:
An error occurred while attempting to decode the Jwt: the given typ value needs to be one of [JWT]