Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

User's OAuth2 Token into RestTemplate

How to correctly get the users's session oauth2 token ?

I implemented an OAuth2 Authorization/Resource server using spring-security-oauth2-autoconfigure.

I implemented a client app, that uses the authorization server to login the user and gets his access token. The login phase is working perfectly and so the retreive of the login data (using the access token by the oauth2 filters). The Principal in the client app requests correctly shows all authorities filled by the authorization server.

I'd like to use the client app as a proxy to send Rest Request using the given Access Token of the user that requested the call.

I already tried to use @EnableOAuth2Client but that does not work. The OAuth2RestTemplate is null when tried to be autowired.

I had to reimplement a request scoped bean of a RestTemplate which get the tokenValue from the SecurityContext. This works, but I do not find this clean. This behavior is quite common, so I should miss something.

application.yml

spring:
  application.name: client
  security:
    oauth2:
      client:
        registration:
          myclient:
            client-id: client-id
            client-secret: client-secret
            redirect-uri: http://localhost:8081/login/oauth2/code/
            authorization-grant-type: authorization_code

        provider:
          myclient:
            authorization-uri: http://localhost:8090/oauth/authorize
            token-uri: http://localhost:8090/oauth/token
            user-info-uri: http://localhost:8090/me
            user-name-attribute: name

SecurityConfiguration

@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // @formatter:off
        http.authorizeRequests()
            .antMatchers("/", "/login").permitAll()
            .antMatchers("/admin/**").hasRole("ADMIN")
            .anyRequest().authenticated()
        .and().oauth2Login()
        .and().oauth2Client()
        ;
        // @formatter:on

    }

    @Bean
    @Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS)
    @Qualifier("oauth2RestTemplate")
    public RestTemplate oauth2RestTemplate() {
        RestTemplate restTemplate = new RestTemplate();
        restTemplate.getInterceptors().add(new ClientHttpRequestInterceptor() {

            @Override
            public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution)
                    throws IOException {

                Authentication auth = SecurityContextHolder.getContext().getAuthentication();

                if (auth != null && auth.isAuthenticated() && auth instanceof OAuth2AuthenticationToken) {
                    @SuppressWarnings("unchecked")
                    Map<String, Object> details = (Map<String, Object>) ((OAuth2AuthenticationToken) auth).getPrincipal().getAttributes().get("details");
                    String tokenValue = (String) details.get("tokenValue");

                    if (tokenValue != null) {
                        request.getHeaders().add("Authorization", "Bearer " + tokenValue);
                    }
                }

                return execution.execute(request, body);
            }
        });


        return restTemplate;
    }
}

In WebController

    private @Autowired @Qualifier("oauth2RestTemplate") RestTemplate oauth2RestTemplate;

    @GetMapping("/remote")
    public Map<String, Object> remote() {
        @SuppressWarnings("unchecked")
        Map<String, Object> resp = oauth2RestTemplate.getForObject(URI.create("http://localhost:8090/api/test"), Map.class);

        return resp;
    }

It works, but I do not think I should configure the RestTemplate myself.

like image 992
CreatixEA Avatar asked Aug 09 '26 00:08

CreatixEA


1 Answers

Unfortunately, you have to define OAuth2RestTemplate. However, this is a more clean implementation.

@Bean
public OAuth2RestTemplate oauth2RestTemplate() {

    ClientCredentialsResourceDetails resourceDetails = new ClientCredentialsResourceDetails();
    resourceDetails.setAccessTokenUri(format("%s/oauth/token", authServerUrl));
    resourceDetails.setClientId("client_id");
    resourceDetails.setClientSecret("client_secret");
    resourceDetails.setGrantType("client_credentials");
    resourceDetails.setScope(asList("read", "write"));

    DefaultOAuth2ClientContext clientContext = new DefaultOAuth2ClientContext();
    return new OAuth2RestTemplate(resourceDetails, clientContext);
}

In this case, your Resource server will communicate with the authorization server on your behalf using its own credentials.

like image 99
Alan Sereb Avatar answered Aug 11 '26 15:08

Alan Sereb