How to use the Spring OAuth2 client to retrieve an access token only? – Spring-boot

by
Ali Hasan
access-token openid-connect spring-boot spring-security

Quick Fix: Use the DefaultReactiveOAuth2AuthorizedClientManager within request context by defining it as below:

@Bean
public ReactiveOAuth2AuthorizedClientManager authorizedClientManager(final ReactiveClientRegistrationRepository clientRegistrationRepository,
                                                                  final ReactiveOAuth2AuthorizedClientService clientService) {
    ReactiveOAuth2AuthorizedClientProvider authorizedClientProvider = ReactiveOAuth2AuthorizedClientProviderBuilder.builder()
            .clientCredentials()
            .build();

    AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager authorizedClientManager = new AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager(clientRegistrationRepository, clientService);

    authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);
    return authorizedClientManager;
}

And use the client as follows:

public String getAccessToken(ReactiveOAuth2AuthorizedClientManager manager){
    OAuth2AuthorizeRequest req = OAuth2AuthorizeRequest.withClientRegistrationId("auth0").principal("N/A").build();
    OAuth2AuthorizedClient client = manager.authorize(req).block();
    return client.getAccessToken().getTokenValue();
}

The Problem:

I am trying to use the Spring OAuth2 client to retrieve an access token only. I have configured the application.yml file with the appropriate settings and created a ClientManager, but I am not sure how to use the ClientManager to get a client to authenticate using the token endpoint.

The Solutions:

Solution 1: Using `AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager`

The provided solution suggests modifying the bean definition of ReactiveOAuth2AuthorizedClientManager to use AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager. This change is necessary because DefaultReactiveOAuth2AuthorizedClientManager is intended for use within a request context.

By using AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager, we can retrieve an access token by following these steps:

  1. Create an OAuth2AuthorizeRequest object to specify the client registration ID ("auth0" in this case) and the principal.
  2. Call authorize on the client manager with the request object to obtain an OAuth2AuthorizedClient.
  3. Retrieve the access token value from the authorized client.

Here’s a code example for retrieving the access token:

public String getAccessToken(ReactiveOAuth2AuthorizedClientManager manager) {
    OAuth2AuthorizeRequest req = OAuth2AuthorizeRequest.withClientRegistrationId("auth0").principal("N/A").build();
    OAuth2AuthorizedClient client = manager.authorize(req).block();
    return client.getAccessToken().getTokenValue();
}

Solution 2: Use an OAuth2ClientProviderBuilder

The Spring OAuth2 client provides a convenient way to retrieve an access token only. To do this, you can use an {@link OAuth2AuthorizedClientProviderBuilder} to create a client provider that supports client credentials. Here’s how you can do it:

import org.springframework.security.oauth2.client.OAuth2AuthorizedClient;
import org.springframework.security.oauth2.client.OAuth2AuthorizedClientManager;
import org.springframework.security.oauth2.client.OAuth2AuthorizedClientProvider;
import org.springframework.security.oauth2.client.OAuth2AuthorizedClientProviderBuilder;
import org.springframework.security.oauth2.client.OAuth2ClientCredentialsGrantRequest;

public class OAuth2AccessTokenRetriever {

    private final OAuth2AuthorizedClientManager authorizedClientManager;

    public OAuth2AccessTokenRetriever(OAuth2AuthorizedClientManager authorizedClientManager) {
        this.authorizedClientManager = authorizedClientManager;
    }

    public String retrieveAccessToken(String clientId, String clientSecret) {
        // Create a client credentials grant request
        OAuth2ClientCredentialsGrantRequest grantRequest = new OAuth2ClientCredentialsGrantRequest(
            clientId,
            clientSecret
        );

        // Create a client provider that supports client credentials
        OAuth2AuthorizedClientProvider clientProvider = OAuth2AuthorizedClientProviderBuilder.builder()
            .clientCredentials()
            .build();

        // Authorize the client using the client provider
        OAuth2AuthorizedClient authorizedClient = authorizedClientManager.authorize(grantRequest, clientProvider);

        // Get the access token from the authorized client
        return authorizedClient.getAccessToken().getTokenValue();
    }
}

Q&A

I was able to create a ClientManager, but not entirely sure why this isn’t done automatically by SpringBoot.

To use the ClientManager, the application context needs to be set up correctly.

How to use the clientManager to get a client to authenticate using the token endpoint

Make necessary modifications to the ClientManager and use the code provided.

Video Explanation:

The following video, titled "Spring Boot and Spring Security with JWT including Access and ...", provides additional insights and in-depth exploration related to the topics discussed in this post.

Play video

This was a fun project, I learned how to secure my API routes, how to authenticate & authorize as well as sending a refresh token.