Description
Summary
Refresh tokens don't support timeouts - if refresh token expires application will keep trying to refresh access token through it forever.
Also all class around OAuth2 client are final which doesn't allow to fix the problem on my side temporary.
Actual Behavior
- App authorizes client and gets access & refresh tokens
- App is making requests through access token
- Access token expires, app is able to refresh
- Now refresh token expires (!)
- Attempt to refresh fails -> request fails
- Any subsequent access leads to attempt to refresh through expired refresh token
- Back to 5.
=> application will never recover
Expected Behavior
In order of preference
Option 1 - allow & handle refresh tokens expiry
Option 2 - add flag to optionally disable refresh tokens in PasswordOAuth2AuthorizedClientProvider
Option 3 - if refresh was attempted and failed remove client from authorizeClientRepository
so the subsequent call starts from scratch allowing to recover
Idea 1 - don't make all classes final, it is difficult to add own behaviour. I remember nearly all classes in Spring used to be opened for extension.
Configuration
@Bean
public WebClient webClient(ClientRegistrationRepository clientRegistrationRepository, OAuth2AuthorizedClientService authorizedClientService) {
AuthorizedClientServiceOAuth2AuthorizedClientManager manager = new AuthorizedClientServiceOAuth2AuthorizedClientManager(clientRegistrationRepository, authorizedClientService);
manager.setAuthorizedClientProvider(new DelegatingOAuth2AuthorizedClientProvider(
new RefreshTokenOAuth2AuthorizedClientProvider(),
new PasswordOAuth2AuthorizedClientProvider()));
Map<String, Object> passwordAttributes = new HashMap<>();
passwordAttributes.put(OAuth2AuthorizationContext.USERNAME_ATTRIBUTE_NAME, "user");
passwordAttributes.put(OAuth2AuthorizationContext.PASSWORD_ATTRIBUTE_NAME, "password");
manager.setContextAttributesMapper(request -> passwordAttributes);
ServletOAuth2AuthorizedClientExchangeFilterFunction oauth2 = new ServletOAuth2AuthorizedClientExchangeFilterFunction(manager);
oauth2.setDefaultClientRegistrationId("oauth-service-to-service-client");
return WebClient.builder()
.filter(oauth2)
.apply(oauth2.oauth2Configuration())
.build();
}
Version
5.2