spring-cloud-gateway icon indicating copy to clipboard operation
spring-cloud-gateway copied to clipboard

Unable to customize ReactiveOAuth2AccessTokenResponseClient for refresh token

Open alexist opened this issue 6 months ago • 0 comments

Hi,

I'm using spring boot 3.3.1/spring-cloud-starter-gateway (reactive)/ spring-boot-starter-oauth2-client. My Oauth2 / OIDC Provider is behind an HTTP Proxy. I need to customize the WebClient, in order to configure the HttpProxy.

Following the documentation, i have created 2 beans :

@Bean
public ReactiveOAuth2AccessTokenResponseClient<OAuth2AuthorizationCodeGrantRequest> authorizationCodeAccessTokenResponseClient() {
    WebClientReactiveAuthorizationCodeTokenResponseClient accessTokenResponseClient =
			new WebClientReactiveAuthorizationCodeTokenResponseClient();
		accessTokenResponseClient.setWebClient(webClient());

	return accessTokenResponseClient;
}

@Bean
public ReactiveOAuth2AccessTokenResponseClient<OAuth2RefreshTokenGrantRequest> refreshTokenAccessTokenResponseClient() {
	WebClientReactiveRefreshTokenTokenResponseClient accessTokenResponseClient =
			new WebClientReactiveRefreshTokenTokenResponseClient();
		accessTokenResponseClient.setWebClient(webClient());

	return accessTokenResponseClient;
}

private static WebClient webClient() {
    final HttpClient httpClient = HttpClient.create().proxyWithSystemProperties();
    return WebClient.builder()
                    .clientConnector(new ReactorClientHttpConnector(httpClient))
                    .build();
}

When the application receive the authorization code, spring security call the token endpoint and receive the access token. The custom bean WebClientReactiveAuthorizationCodeTokenResponseClient is used, and the http query go through the proxy

But when spring security call the endpoint to refresh the token, it doesn't work. The custom WebClientReactiveAuthorizationCodeTokenResponseClient is not used.

I put some breakpoint, the second bean is instantiated but in method RefreshTokenReactiveOAuth2AuthorizedClientProvider.authorize, the accessTokenResponseClient is not my custom bean, but the default one :

@Override
public Mono<OAuth2AuthorizedClient> authorize(OAuth2AuthorizationContext context) {
	return Mono.just(refreshTokenGrantRequest)
			.flatMap(this.accessTokenResponseClient::getTokenResponse) // <------ accessTokenResponseClient is the default one
			.onErrorMap(OAuth2AuthorizationException.class,
					(e) -> new ClientAuthorizationException(e.getError(), clientRegistration.getRegistrationId(), e))
			.map((tokenResponse) -> new OAuth2AuthorizedClient(clientRegistration, context.getPrincipal().getName(),
					tokenResponse.getAccessToken(), tokenResponse.getRefreshToken()));

The workaround i found is to apply the configuration that should be used prior to 6.3 'Customize WebClient for OAuth2 Client (prior to 6.3') and publish a bean of type ReactiveOAuth2AuthorizedClientManager

I originally posted the issue on spring secutiry project https://github.com/spring-projects/spring-security/issues/15657 , but in fact it works when spring cloud gateway is not in the classpath. It may be related to https://github.com/spring-cloud/spring-cloud-gateway/issues/3493, but i'm not sure.

alexist avatar Aug 22 '24 07:08 alexist