Ostap Maliuvanchuk
Ostap Maliuvanchuk

Reputation: 1175

refresh token is null using Spring Security OAuth2

I am trying to integrate Google OAuth 2 using Spring Security. Everything works well, but refresh_token is null.

Here is my config:

@Bean
public OAuth2ProtectedResourceDetails googleOAuth2Details() {
    AuthorizationCodeResourceDetails googleOAuth2Details = new AuthorizationCodeResourceDetails();
    googleOAuth2Details.setAuthenticationScheme(form);
    googleOAuth2Details.setClientAuthenticationScheme(form);
    googleOAuth2Details.setClientId(googleClientId);
    googleOAuth2Details.setClientSecret(googleClientSecret);
    googleOAuth2Details.setUserAuthorizationUri(googleOAuthUri);
    googleOAuth2Details.setAccessTokenUri(googleTokenUrl);
    googleOAuth2Details.setScope(asList("openid","email"));
    return googleOAuth2Details;
}

I read that in order to get refresh_token, access_type has to be "offline". But what is the way to set it in Spring?

Upvotes: 1

Views: 2529

Answers (3)

bedla.czech
bedla.czech

Reputation: 1219

You can create customizing implementation of OAuth2AuthorizationRequestResolver and add additionalParameters(..) with "access_type"="offline" as described at Spring security documentation.

@EnableWebSecurity
public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter {
    private final ClientRegistrationRepository clientRegistrationRepository;

    public OAuth2LoginSecurityConfig(ClientRegistrationRepository clientRegistrationRepository) {
        this.clientRegistrationRepository = clientRegistrationRepository;
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .authorizeRequests()
                .anyRequest().authenticated()
                .and()
                .oauth2Login()
                .authorizationEndpoint()
                .authorizationRequestResolver(
                        new CustomAuthorizationRequestResolver(
                                this.clientRegistrationRepository));
    }
}

public class CustomAuthorizationRequestResolver implements OAuth2AuthorizationRequestResolver {
    private final OAuth2AuthorizationRequestResolver defaultAuthorizationRequestResolver;

    public CustomAuthorizationRequestResolver(ClientRegistrationRepository clientRegistrationRepository) {
        this.defaultAuthorizationRequestResolver = new DefaultOAuth2AuthorizationRequestResolver(clientRegistrationRepository, OAuth2AuthorizationRequestRedirectFilter.DEFAULT_AUTHORIZATION_REQUEST_BASE_URI);
    }

    @Override
    public OAuth2AuthorizationRequest resolve(HttpServletRequest request) {
        final OAuth2AuthorizationRequest authorizationRequest = this.defaultAuthorizationRequestResolver.resolve(request);
        return authorizationRequest != null ? customAuthorizationRequest(authorizationRequest) : null;
    }

    @Override
    public OAuth2AuthorizationRequest resolve(HttpServletRequest request, String clientRegistrationId) {
        final OAuth2AuthorizationRequest authorizationRequest = this.defaultAuthorizationRequestResolver.resolve(request, clientRegistrationId);
        return authorizationRequest != null ? customAuthorizationRequest(authorizationRequest) : null;
    }

    private OAuth2AuthorizationRequest customAuthorizationRequest(OAuth2AuthorizationRequest authorizationRequest) {
        Map<String, Object> additionalParameters = new LinkedHashMap<>(authorizationRequest.getAdditionalParameters());
        additionalParameters.put("access_type", "offline");
        return OAuth2AuthorizationRequest.from(authorizationRequest)
                .additionalParameters(additionalParameters)
                .build();
    }
}

Upvotes: 1

Hans Z.
Hans Z.

Reputation: 53888

Try this: you may add the parameter "hard-configured" to googleOAuthUri, so:

googleOAuthUri = googleOAuthUri + "?access_type=offline";
googleOAuth2Details.setUserAuthorizationUri(googleOAuthUri);

and hopefully Spring does the right thing when adding the other parameters.

Also be aware that the refresh_token is only returned the first time that a user grants access to your client. Subsequent authorization requests will not produce a new refresh_token since it is assumed that your client has stored that from the first request.

Upvotes: 2

Sergey Yamshchikov
Sergey Yamshchikov

Reputation: 1019

I'm afraid that 'access_type' param is not in scope of OAUTH2 Authorization (RFC 6749) and Spring doesn't have it by default, so you need to add it manually. Unfortunately I don't now correct way to do it right now, but I think that 'OAuth2RestTemplate#getAccessToken' is a good place to start the investigation.

Also this post may be useful for you.

Upvotes: 1

Related Questions