Expected Behavior

OidcIdTokenDecoderFactory should provide a setter method to configure "jwtProcessorCustomizer" for applying it on NimbusJwtDecoder instances.

This allow application to configure JWE Key Selector via the customizer, and enabling id token decryption, which already supported by NimbusJwtDecoder / DefaultJWTProcessor.

Current Behavior

When integrating with an authorization server that does return encrypted id_token using JWE, Spring OAuth Login is failed for processing id_token, due to missing "jweKeySelector" in DefaultJWTProcessor.

Context

Without the suppose changes on OidcIdTokenDecoderFactory, I end up need to rewrite OidcIdTokenDecoderFactory.

Comment From: ufkl

The following are the proposed on OidcIdTokenDecoderFactory.

public class OidcIdTokenDecoderFactory implements JwtDecoderFactory<ClientRegistration> {
    ...

    private Consumer<ConfigurableJWTProcessor<SecurityContext>> jwtProcessorCustomizer = (processor) -> {
    };

    /**
     * Generate {@link JwtDecoder} based on client registration.
     *
     * @param clientRegistration client registration
     * @return new JwtDecoder
     */
    private NimbusJwtDecoder buildDecoder(ClientRegistration clientRegistration) {
        JwsAlgorithm jwsAlgorithm = this.jwsAlgorithmResolver.apply(clientRegistration);
        if (jwsAlgorithm != null && SignatureAlgorithm.class.isAssignableFrom(jwsAlgorithm.getClass())) {
            ...
            return NimbusJwtDecoder.withJwkSetUri(jwkSetUri)
                    .jwsAlgorithm((SignatureAlgorithm) jwsAlgorithm)
                    .jwtProcessorCustomizer(this.jwtProcessorCustomizer)
                    .build();
        }
        if (jwsAlgorithm != null && MacAlgorithm.class.isAssignableFrom(jwsAlgorithm.getClass())) {
            ..
            return NimbusJwtDecoder.withSecretKey(secretKeySpec)
                    .macAlgorithm((MacAlgorithm) jwsAlgorithm)
                    .jwtProcessorCustomizer(this.jwtProcessorCustomizer)
                    .build();
        }
        ...
    }

    /**
     * Customise JWT Processor, e.g. JWT decryption.
     *
     * @param jwtProcessorCustomizer customizer
     */
    public void setJwtProcessorCustomizer(Consumer<ConfigurableJWTProcessor<SecurityContext>> jwtProcessorCustomizer) {
        this.jwtProcessorCustomizer = jwtProcessorCustomizer;
    }
}

Comment From: jzheaux

@ufkl thanks for the suggestion. Given that the other methods are multi-tenant, I think that setJwtProcessorCustomizer should instead be setJwtProcessorCustomizerFactory.

Are you able to submit a PR adding the method?

Comment From: ufkl

Sure. Let me look at contributing guidelines first I submit PR.

Comment From: jgrandja

@ufkl @jzheaux I don't think we should add setJwtProcessorCustomizer(Consumer<ConfigurableJWTProcessor<SecurityContext>>.

The main reason is that we only expose Nimbus API's in a Nimbus implementation, which has the Nimbus prefix in class name, e.g. NimbusJwtDecoder, NimbusJwtClientAuthenticationParametersConverter, NimbusOpaqueTokenIntrospector, etc.

Even though OidcIdTokenDecoderFactory uses Nimbus internally, no Nimbus API's are exposed at the moment so we technically can change the internal implementation if needed.

Without the suppose changes on OidcIdTokenDecoderFactory, I end up need to rewrite OidcIdTokenDecoderFactory

Most of the components used in OidcIdTokenDecoderFactory can be reused in a custom implementation of JwtDecoderFactory<ClientRegistration>. Please see this comment.

Comment From: jzheaux

The main reason is that we only expose Nimbus API's in a Nimbus implementation

Good catch, @jgrandja. We don't want to reference Nimbus in a non-Nimbus public API.