Description
Describe the bug
If you are setting up a NimbusJwtDecoder using Spring Security, we have the possibility to provide a Cache that will be used for storing the JWK Set. This is a good feature, since we can then override the default TTL, instead of using DefaultJWKSetCache, which has a default refresh time of 5 minutes.
Reference to documentation: https://docs.spring.io/spring-security/reference/servlet/oauth2/resource-server/jwt.html#oauth2resourceserver-jwt-timeouts
The issue occurs when you use your own cache implementation, and you try to decode a JWT with an unknown KID. I would expect this to trigger a refresh of the JWK set, but this is not what is happening.
Example code of setup:
var jwkSetCache = new ConcurrentMapCache("jwkSetCache", CacheBuilder.newBuilder()
.expireAfterWrite(Duration.ofMinutes(30))
.build().asMap(), false);
var decoder = NimbusJwtDecoder.withJwkSetUri(jwkSetUri)
.cache(jwkSetCache)
.build();
We end up here with an unknown KID: https://bitbucket.org/connect2id/nimbus-jose-jwt/src/43b5435c548d70ce250afe6f932a6a55b3833bb8/src/main/java/com/nimbusds/jose/jwk/source/RemoteJWKSet.java#lines-486, and we expect the JWK set to be refetched.
The problem is that the NimbusJwtDecoder.java always uses the CachingResourceRetriever, even when it encounters an unknown KID: https://github.com/spring-projects/spring-security/blob/main/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/NimbusJwtDecoder.java#L406-L407. This will lead to the JWK set only being fetched from the cache, and not refetched from the remote source.
To Reproduce
- Setup NimbusJwtDecoder with a Cache and remote JWK set.
- Try to decode a JWT signed with a KID not present in the JWK set.
- Expect NimbusJwtDecoder to refetch JWK set from jwksetUri.
If we don't specify a cache to the NimbusJwtDecoder builder, it works as expected. The jwk set is refetched when encountering a signed JWS with an unknown KID.
Expected behavior
I expect JWK set to be refetched when encountering a KID not present in the current cached JWK set.