Expected Behavior
As the title says ... the NimbusReactiveJwtDecoder is created with default web client initialized statically. There is no way to change it. It should be possible to change the WebClient passed to NimbusReactiveJwtDecoder.
Current Behavior
Compared to other parts of the reactive stack, it is currently impossible to customize WebClient passed to NimbusReactiveJwtDecoder
Context
I have a Keycloak instance behind a self-signed SSL certificate. I have configured webclient instance to get it using WebClientSsl builder. But I can't pass that WebClient to NimbusReactiveJwtDecoder.
Comment From: jzheaux
I believe it is already possible:
@Bean
ReactiveJwtDecoder jwtDecoder() {
return NimbusReactiveJwtDecoder.withIssuerLocation("https://example.org/issuer")
.webClient(web).build();
}
or
@Bean
ReactiveJwtDecoder jwtDecoder() {
return NimbusReactiveJwtDecoder.withJwkSetUri("https://example.org/jwks")
.webClient(web).build();
}
Are you having trouble with either of these approaches?
Comment From: krezovic
Hi @jzheaux, the problem is not wit NimbusReactiveJwtDecoder itself, but rather one that is created within ReactiveOidcIdTokenDecoderFactory.
Examine the line: https://github.com/spring-projects/spring-security/blob/main/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/oidc/authentication/ReactiveOidcIdTokenDecoderFactory.java#L166
There is no way to pass WebClient to that specific instance, which is not created by myself and cannot be easily overriden due to private methods all around ...
Comment From: jzheaux
I see, sorry that I missed that.
I think it would be reasonable to add a method to ReactiveOidcTokenDecoderFactory for specifying the WebClient. instance. Something like:
public void setWebClientFactory(Function<ClientRegistration, WebClient> webClientFactory) {
// ...
}
Are you able to provide a PR to add that to ReactiveOidcIdTokenDecoderFactory and OidcIdTokenDecoderFactory?
Comment From: ZIRAKrezovic
Hi @jzheaux, I may be able to do it during the oncoming holidays.
Comment From: jgrandja
@jzheaux
Are you able to provide a PR to add that to
ReactiveOidcIdTokenDecoderFactoryandOidcIdTokenDecoderFactory?
I don't think we should enhance OidcIdTokenDecoderFactory. Please see this comment for further details.
Furthermore, given that we will eventually provide support for the new RestClient, this would result in deprecating usages of RestOperations.
Comment From: jzheaux
Closed in favor of https://github.com/spring-projects/spring-security/pull/14357
Comment From: jzheaux
Based on this comment as well as the simplicity of this construction, I think the following arrangement is preferred:
@Component
public class MyJwtDecoderFactory implements JwtDecoderFactory<ClientRegistration> {
@Cacheable
public JwtDecoder createDecoder(ClientRegistration registration) {
String issuerUri = client.getProviderDetails().getIssuerUri();
NimbusJwtDecoder decoder = NimbusJwtDecoder.withIssuerLocation(issuerUri).restOperations(this.rest).build();
decoder.setJwtValidator(new DelegatingOAuth2TokenValidator<>(
JwtValidators.createDefault(), new OidcIdTokenValidator(client)));
decoder.setClaimTypeConverter(
new ClaimTypeConverter(OidcIdTokenDecoderFactory.createDefaultClaimTypeConverters()));
return decoder;
}
}
Also, recent 6.3 changes will simplify this to:
@Component
public class MyJwtDecoderFactory implements JwtDecoderFactory<ClientRegistration> {
@Cacheable
public JwtDecoder createDecoder(ClientRegistration registration) {
String issuerUri = client.getProviderDetails().getIssuerUri();
NimbusJwtDecoder decoder = NimbusJwtDecoder.withIssuerLocation(issuerUri).restOperations(this.rest).build();
decoder.setJwtValidator(JwtValidators.createDefaultWithValidators(new OidcIdTokenValidator(client)));
decoder.setClaimTypeConverter(OidcIdTokenDecoderFactory.createDefaultClaimTypeConverter());
return decoder;
}
}
As such, I think we should revert the setWebClient and setRestOperations changes for now. We can always add them back in later on should this prove to be an issue.
Comment From: neoXfire
Hi @jzheaux,
For info, i am not a OIDC expert so please double check what I am saying just after 😃
Customizing the WebClient instance must be needed for something as simple as customizing the proxy policy to adapt to end user technical environment like with the issue https://github.com/spring-projects/spring-security/issues/8882
The ReactiveOidcIdTokenDecoderFactory provided by default in Spring Security offers a lot of funcitonnalities like handling multipe jws algorithms (Signature, Mac, Secret...) and default claim types mappings for example.
Reimplementing a JwtDecoderFactory from scratch could be as simple as the examples you provided in your previous comment. But I think it is only applicable on situations where you are totally aware of the technical environment where your application is going to be deployed. In other cases, it means saying goodbye to some of the functionnalities provided by spring-security in the default implementation. My guess is that those are the functionnalities which make the library working smoothly with a lot of OIDC solution providers by default.
I was very happy with https://github.com/spring-projects/spring-security/pull/14357 merge. It is sad that was reverted because in my case the only solution I see right now is copy pasting the ReactiveOidcIdTokenDecoderFactory tweaking the class as you initially proposed. Do you think it can be added back ?