-
Notifications
You must be signed in to change notification settings - Fork 5.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
RefreshTokenOAuth2AuthorizedClientProvider does not handle expired refresh token #7583
Comments
Few days earlier I created SO question on this topic: https://stackoverflow.com/questions/58604304/how-to-re-initialize-password-grant-in-spring-security-5-2-oauth |
@janzyka This is an interesting use case. Can you provide more details of the error when the As per spec, in 6. Refreshing an Access Token:
If you look at Section 5.2, it seems to me that the provider would return
Our design preference is "composition over inheritance". Can you be more specific on what you are looking for? Is there a specific class you would like to extend? |
@jgrandja First of all, thank you very much for following up! I really appreciate it. Error on our proprietary corporate OAuth2 is
I agree this is not according to the spec - in this particular case it should be indeed Talking from a perspective of long running service with backend ( This leads me to the second part of the question, final classes. I had 2 problems which could have been solved by extending existing
Generally subclassing allows me to:
Having said that - composition over inheritance is default choice if possible, no doubt about that. |
Agreed. I'll give this some thought and see if we can deliver an improvement here.
As you may have noticed, As already mentioned, I prefer composition over inheritance. It's very difficult to modify a
There is a way. You can provide a customized Either way, I'll leave this issue open and think about some recovery mechanism that may be added as an improvement. |
Regarding disable refresh tokens. Ideally (to me) it would be as easy as not registering the My solution was as follows:
public MyCopiedPasswordOAuth2AuthorizedClientProvider() {
this.supportRefreshTokens = true;
}
public MyCopiedPasswordOAuth2AuthorizedClientProvider(boolean supportRefreshTokens) {
this.supportRefreshTokens = supportRefreshTokens;
}
@Override
@Nullable
public OAuth2AuthorizedClient authorize(OAuth2AuthorizationContext context) {
...
...
...
return new OAuth2AuthorizedClient(clientRegistration, context.getPrincipal().getName(),
tokenResponse.getAccessToken(), supportRefreshTokens ? tokenResponse.getRefreshToken() : null);
} The effect is the same as you suggested but it feels a bit less complex to me. Talking about inheritance, if the class were public, I would just extend it, call If you would like me to turn this into PR I would be glad to do it. |
You could also implement a delegation-based approach as follows: public OAuth2AuthorizedClientProvider customPasswordAuthorizedClientProvider() {
return new OAuth2AuthorizedClientProvider() {
final PasswordOAuth2AuthorizedClientProvider delegate = new PasswordOAuth2AuthorizedClientProvider();
@Override
public OAuth2AuthorizedClient authorize(OAuth2AuthorizationContext context) {
OAuth2AuthorizedClient authorizedClient = delegate.authorize(context);
// Always exclude refresh token (if available)
return new OAuth2AuthorizedClient(
authorizedClient.getClientRegistration(),
authorizedClient.getPrincipalName(),
authorizedClient.getAccessToken());
}
};
}
|
Cool, that is probably even better. I had to fix the reverted skew sign bug as well along the way but if it was purely for inheritance argument, you are 100% correct. Thanks for the tip! |
The fix is available in 5.2.1 see #7511 |
can you suggest if this is right approach to refresh token? https://stackoverflow.com/questions/59144160/spring-oauth2-client-automatically-refresh-expired-access-token |
@janzyka This is now fixed via #7840. See RemoveAuthorizedClientOAuth2AuthorizationFailureHandler, which is the default |
I'm running into a similar issue to this. But maybe I'm just misunderstanding the intended design and use of this functionality. I currently have a It was my understanding that the following would be the sequence of events:
Does step 3 not happen automatically? From what I can tell when a request is made once the refresh token has expired the Do I need to explicitly perform a retry on my client
.get()
.uri("")
.retrieve()
.bodyToMono(Object.class)
.retryWhen(Retry.max(1).filter(e -> (e instanceof OAuth2AuthorizationException))); |
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
=> 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 recoverIdea 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
Version
5.2
Sample
The text was updated successfully, but these errors were encountered: