Search code examples
spring-bootspring-securityoauth-2.0microservices

Does spring security provide out of the box feature to retrieve and use OAuth2 token from a resource server


We have a Springboot application (let’s say microservice-A) and there is a requirement that we should add a HTTP Authorisation header with the OAuth2 token to access one of our other microservice (let’s say microservice-B). Also we are said that we can retreive this OAuth2 token by sending a HTTP POST request with Grant_type, Scope and basic authentication username and password to the same microservice-B.

Now my doubt is, do we have any kind of out of the box support from Spring security to automatically retrieve this OAuth2 token from microservice-B whenever it expires and send the subsequent HTTP requests. Or is this not required at all and I should just retrieve the OAuth2 token first by sending a normal HTTP POST request from microservice-A and then send the subsequent requests. (This way I might have to retrieve the OAuth2 token every time I want to send a request or save the token and retrieve it when it expires)

Microservice-A is the “client" Microservice-B is the “resource server”


Solution

  • Found a solution using org.springframework.boot:spring-boot-starter-oauth2-client. Below are the configurations required to configure a OAUTH2 based WebClient that can automatically fetch the OAUTH2 token from auth-server (Microservice-B) and access resource-server (Microservice-B).

    application.properties

    oauth2.client.registration.pgw.scope=all
    oauth2.client.registration.pgw.client-id=client
    oauth2.client.registration.pgw.client-secret=secret
    oauth2.client.provider.pgw.token-uri=http://localhost:8082/oauth/token
    

    Oauth2ClientConfiguration.java

    @Configuration
    public class Oauth2ClientConfiguration {
            
        @Bean
        public ReactiveClientRegistrationRepository getRegistration(
                @Value("${oauth2.client.provider.pgw.token-uri}") String tokenUri,
                @Value("${oauth2.client.registration.pgw.client-id}") String clientId,
                @Value("${oauth2.client.registration.pgw.client-secret}") String clientSecret,
                @Value("${oauth2.client.registration.pgw.scope}") String scope) {
            
            ClientRegistration registration = ClientRegistration
                                                    .withRegistrationId(OAUTH2_CLIENT_REGISTRATION_ID)
                                                    .tokenUri(tokenUri)
                                                    .clientId(clientId)
                                                    .clientSecret(clientSecret)
                                                    .authorizationGrantType(CLIENT_CREDENTIALS)
                                                    .scope(scope)
                                                    .build();
            
            return new InMemoryReactiveClientRegistrationRepository(registration);
        }
        
        @Bean
        public WebClient webClient(ReactiveClientRegistrationRepository clientRegistrations) {
            InMemoryReactiveOAuth2AuthorizedClientService clientService = 
                    new InMemoryReactiveOAuth2AuthorizedClientService(clientRegistrations);
            
            AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager authorizedClientManager = 
                    new AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager(clientRegistrations, clientService);
            
            ServerOAuth2AuthorizedClientExchangeFilterFunction oauth = 
                    new ServerOAuth2AuthorizedClientExchangeFilterFunction(authorizedClientManager);
            oauth.setDefaultClientRegistrationId(OAUTH2_CLIENT_REGISTRATION_ID);
            
            return WebClient.builder().filter(oauth).build();
        }
    
    }
    

    Then we can access use this WebClient bean to send HTTP request to resource-server which will take care of fetching and managing the OAUTH2 token

    webClient.get().uri("http://localhost:8080/api/private").retrieve().bodyToMono(String.class).block();