Why isn't OAuth2 client refreshing expired access_token?

2.4k Views Asked by At

I've got a client app configured with @EnableOAuth2Sso and @EnableZuulProxy, and a resource server (separate app) configured with @EnableOAuth2Resource. I can see that the client correctly authenticates to the resource server with Authorization: Bearer {access_token here}, but when once the access token expires, the proxied resource server request fails permanently.

[Edited]

I've modified my resource server by providing a custom RemoteTokenServices bean that uses OpenAM's /tokeninfo endpoint to decide whether an access_token remains valid. (The Spring-provided RemoteTokenServices bean attempts to POST, which gets a 405 from OpenAM). When I detect the access_token is invalid, I throw InvalidTokenException from my.spring.oauth2.OpenAMRemoteTokenServices#loadAuthentication. Now, my resource server is (I think correctly) sending HTTP 401 on the response to the client, in the case where the access_token has expired.

Still, the client is not attempting to refresh the token.

Maybe my mental model is wrong. I expect the client, in the case of expired access_token, to automatically use the refresh_token to obtain a new one. I don't know whether I think it should proactively refresh an access_token (within some epsilon before expiry time), or wait for a downstream request to fail and try refreshing then. But my client appears to be doing neither, and I can't tell why not.

1

There are 1 best solutions below

0
On BEST ANSWER

As stated in this git issue: https://github.com/spring-guides/tut-spring-security-and-angular-js/issues/140, the problem might be related to the fact that with versions 1.4 and above of spring boot the Zuul filter that handles the downstream of access tokens to services (org.springframework.cloud.security.oauth2.proxy.OAuth2TokenRelayFilter) is missing a bean of type OAuth2RestTemplate, which is used by the filter itself to automatically handle the refresh_token grant when access tokens expire.

I had the same issue and I solved it by adding in a configuration class the following bean:

@Configuration
public class ZuulConfiguration {
    @Bean
    protected OAuth2RestTemplate oauth2RestTemplate(OAuth2ProtectedResourceDetails resource, 
        OAuth2ClientContext context) {

        return new OAuth2RestTemplate(resource, context);
    }
}