The helpers in JwtDecoders (e.g. fromOidcIssuerLocation) and JwtValidators should accept an optional parameter for a Clock. (just like it is the case for OidcIdTokenValidator https://github.com/spring-projects/spring-security/issues/8019)

Current Behavior

The System Clock is used by JwtTimestampValidator. Changing this is not possible through the current API because JwtTimestampValidator is not exposed (it's composed into a DelegatingOAuth2TokenValidator but that's also not exposed)

Context

Providing the current time is necessary to write stable tests as well as tests that shift time (for example to test expiry).

The current workaround is to build the JwtDecoder by hand. However, e.g. for the case of fromOidcIssuerLocation this is also non-trivial because it relies on org.springframework.security.oauth2.jwt.JwtDecoderProviderConfigurationUtils which is package private)

Comment From: jzheaux

Thanks for the suggestion, @marndt-gcx.

I believe you can change the clock like so:

@Bean 
JwtDecoder jwtDecoder() {
    JwtTimestampValidator validator = new JwtTimestampValidator();
    validator.setClock(clock);
    NimbusJwtDecoder jwtDecoder = NimbusJwtDecoder.withJwkSetUri(jwkSetUri).build();
    jwtDecoder.setJwtValidator(validator);
    return jwtDecoder;
}

JwtDecoders and JwtValidators - being utilities as they are - aren't the place to be exposing validator configuration. They are for when the defaults suffice.

In this particular case, I believe that the existing support is simple enough for the level of frequency that this kind of thing is needed.

I'm going to close this ticket as having been addressed, but please feel free to add to it if you feel there's more to discuss.

Comment From: michael-arndt-gcx

Thanks for the feedback!

While your example looks simple enough, I cannot reproduce this simplicity for the mentioned fromOidcIssuerLocation.

As far as I can see I need to extract the configuration from the oidcIssuerLocation, which is done JwtDecoderProviderConfigurationUtils.getConfigurationForOidcIssuerLocation, however, this is an internal class. Further the issuer must be validated (as in JwtDecoderProviderConfigurationUtils.validateIssuer) etc.

Anyway, I've reevaluated the need for testing this and concluded that I should stub the whole JwtAuthenticationProvider. Maybe that's the better solution to begin with 😉

Comment From: jzheaux

I'm glad you found something that worked for you! The nice thing about mocking the provider is that you don't need to have a mock issuer as part of your test.

There may also be a simpler way, though: Did you already review Spring Security's test support to see if that would address your testing needs better?