NimbusJwtDecoderJwkSupport uses Nimbus's HTTP Client internally to retrieve the JwkSet resource.
We should re-factor to use RestOperations instead and additionally expose a NimbusJwtDecoderJwkSupport.setRestOperations(restOperations) to allow user's the ability to supply a pre-configured RestOperations if needed.
Related #5601
Comment From: mnovoseltsev
Hi @jgrandja , I wanted to set custom rest operations for NimbusJwtDecoderJwkSupport, but it appears that NimbusJwtDecoderJwkSupport instance is created inside of the private method: OidcAuthorizationCodeAuthenticationProvider#getJwtDecoder. So it is impossible to use NimbusJwtDecoderJwkSupport#setRestOperations method.
For more details - https://github.com/spring-projects/spring-security/issues/6255
Comment From: kumarimanjari
Hi @jgrandja , I have a problem in this area with Spring boot starter oAuth2 client version 3.2.0 which internally uses Spring Security 6.2.0, I have below SecurityConfig file -
I am getting below error -
[invalid_id_token] An error occurred while attempting to decode the Jwt: Couldn't retrieve remote JWK set: org.springframework.web.client.ResourceAccessException: I/O error on GET request for "JWK SET URI": issuer-uri
Can someone assist on this issue ?
` required imports
@Configuration @EnableWebSecurity @RequiredArgsConstructor public class SecurityConfig {
@NonNull
private PropertyUtil propertyUtil;
@Bean
public SecurityFilterChain clientSecurityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(requests -> requests.requestMatchers("/", "/api/**").authenticated()
.anyRequest().permitAll())
.oauth2Login(Customizer.withDefaults());
return http.build();
}
@Bean
public OAuth2AccessTokenResponseClient<OAuth2AuthorizationCodeGrantRequest> authorizationCodeAccessTokenResponseClient() {
DefaultAuthorizationCodeTokenResponseClient accessTokenResponseClient = new DefaultAuthorizationCodeTokenResponseClient();
accessTokenResponseClient.setRestOperations(restTemplate());
return accessTokenResponseClient;
}
@Bean
public OAuth2AccessTokenResponseClient<OAuth2RefreshTokenGrantRequest> refreshTokenAccessTokenResponseClient() {
DefaultRefreshTokenTokenResponseClient accessTokenResponseClient = new DefaultRefreshTokenTokenResponseClient();
accessTokenResponseClient.setRestOperations(restTemplate());
return accessTokenResponseClient;
}
@Bean
public OAuth2AccessTokenResponseClient<OAuth2ClientCredentialsGrantRequest> clientCredentialsAccessTokenResponseClient() {
DefaultClientCredentialsTokenResponseClient accessTokenResponseClient = new DefaultClientCredentialsTokenResponseClient();
accessTokenResponseClient.setRestOperations(restTemplate());
return accessTokenResponseClient;
}
@Bean
public OAuth2AccessTokenResponseClient<JwtBearerGrantRequest> jwtBearerAccessTokenResponseClient() {
DefaultJwtBearerTokenResponseClient accessTokenResponseClient = new DefaultJwtBearerTokenResponseClient();
accessTokenResponseClient.setRestOperations(restTemplate());
return accessTokenResponseClient;
}
@Bean
public JwtDecoder jwtDecoder() {
Proxy proxy = new Proxy(Proxy.Type.HTTP,
new InetSocketAddress(propertyUtil.getString(PropertyConstants.INTERNET_PROXY_HOST),
propertyUtil.getInt(PropertyConstants.INTERNET_PROXY_PORT)));
SimpleClientHttpRequestFactory clientHttpRequestFactory = new SimpleClientHttpRequestFactory();
clientHttpRequestFactory.setProxy(proxy);
ClientHttpRequestFactory bufferedRequestFactory = new BufferingClientHttpRequestFactory(clientHttpRequestFactory);
RestTemplate restTemplate = new RestTemplate(bufferedRequestFactory);
return NimbusJwtDecoder
.withJwkSetUri(jwkSetUri)
.restOperations(restTemplate).build();
}
@Bean
RestTemplate restTemplate() {
SimpleClientHttpRequestFactory clientHttpReq = new SimpleClientHttpRequestFactory();
Proxy proxy = new Proxy(Type.HTTP,
new InetSocketAddress(propertyUtil.getString(PropertyConstants.INTERNET_PROXY_HOST),
propertyUtil.getInt(PropertyConstants.INTERNET_PROXY_PORT)));
clientHttpReq.setProxy(proxy);
ClientHttpRequestFactory bufferedRequestFactory = new BufferingClientHttpRequestFactory(clientHttpReq);
RestTemplate restTemplate = new RestTemplate(Arrays.asList(
new FormHttpMessageConverter(),
new OAuth2AccessTokenResponseHttpMessageConverter(),
new MappingJackson2HttpMessageConverter()));
restTemplate.setRequestFactory(bufferedRequestFactory);
List<ClientHttpRequestInterceptor> interceptors = restTemplate.getInterceptors();
if (CollectionUtils.isEmpty(interceptors)) {
interceptors = new ArrayList<>();
}
interceptors.add(new LoggingRestTemplateInterceptor());
// Default Error Handler from spring security
restTemplate.setErrorHandler(new OAuth2ErrorResponseErrorHandler());
// Logging intercepter
restTemplate.setInterceptors(interceptors);
return restTemplate;
}
}`