Spring Security OAuth2 Client Credentials Grant
Tags: java, security, oauth2, springsecurity
Published: 2023-02-21 07:15:06

### Overview

What to do when there is no clear resource owner, or the resource owner is indistinguishable to the client? This is a fairly common scenario. For example, when direct communication between backend systems is required. This article will introduce OAuth2.0 client credential authorization.

The OAuth2.0 documentation describes client credentials grant:
> Clients use the client credentials grant type to obtain access tokens outside the context of a user. This is typically used by clients to access resources about themselves, rather than accessing resources about the user.

In this article, you'll learn about building OAuth2 client credential grants with Spring Security, allowing services to interoperate securely without authenticated users.

OAuth2 client credential authorization is more straightforward than authorization code authorization, and it is usually used for operations such as CRON tasks and other types of backend data processing.


### Client credentials grant flow

When an application requests an access token to access other resources, authorization is done using client credentials, not on behalf of the user.

#### request parameters

##### grant_type（required）

The `grant_type` parameter must be set to `client_credentials`.

##### scope（optional）

Your service can support different scopes for client credential grants.

##### client authentication（required）

The client needs to authenticate this request. Typically, the service will allow additional request parameters `client_id` and `client_secret`, or accept the client ID and secret in the HTTP Basic auth header.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5gnmltvf1ytbw7vzcvxx.png)


> 💡 Note: If you don’t want to read till the end, you can view the [source code](https://github.com/ReLive27/spring-security-oauth2-sample/tree/main/oauth2-client-model) here.Don’t forget to give a star to the project if you like it!


### OAuth2 authorization server

Here we use [Spring Authorization Server](https://spring.io/projects/spring-authorization-server#learn) to build an OAuth2 authorization server. I won't repeat the details here. You can refer to the article [Using JWT with Spring Security OAuth2](https://dev.to/relive27/using-jwt-with-spring-security-oauth2-41jp) to build an authorization server. Here only the difference from the previous authorization code grant process authorization service configuration is described.


#### Configuration

When we create a client using the *RegisteredClient* builder type, we will configure the client to support client credential authorization and simply store it in memory.

```java
@Bean
public RegisteredClientRepository registeredClientRepository() {
  RegisteredClient registeredClient = RegisteredClient.withId(UUID.randomUUID().toString())
    .clientId("relive-client")
    .clientSecret("{noop}relive-client")
    .clientAuthenticationMethods(s -> {
      s.add(ClientAuthenticationMethod.CLIENT_SECRET_POST);
      s.add(ClientAuthenticationMethod.CLIENT_SECRET_BASIC);
    })
    .authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)
    .redirectUri("http://127.0.0.1:8070/login/oauth2/code/messaging-client-model")
    .scope("message.read")
    .clientSettings(ClientSettings.builder()
                    .requireAuthorizationConsent(true)
                    .requireProofKey(false)
                    .build())
    .tokenSettings(TokenSettings.builder()
                   .accessTokenFormat(OAuth2TokenFormat.SELF_CONTAINED)
                   .idTokenSignatureAlgorithm(SignatureAlgorithm.RS256)
                   .accessTokenTimeToLive(Duration.ofSeconds(30 * 60))
                   .refreshTokenTimeToLive(Duration.ofSeconds(60 * 60))
                   .reuseRefreshTokens(true)
                   .build())
    .build();

  return new InMemoryRegisteredClientRepository(registeredClient);
}
```

Above we configured an OAuth2 client and specified **authorizationGrantType** as **client_credentials**:

- **clientId**: relive-client
- **clientSecret**: relive-client
- **redirectUri**: http://127.0.0.1:8070/login/oauth2/code/messaging-client-model
- **scope**: message.read


### Build an OAuth2 resource server with Spring Security

The OAuth2 resource server configuration is consistent with the resource service set-up in this article [Using JWT with Spring Security OAuth2](https://dev.to/relive27/using-jwt-with-spring-security-oauth2-41jp), you can refer to the introduction of OAuth2 resource service in this article, or obtain the source code address of this article at the end of the article to view.

#### Configuration

The OAuth2 resource server provides a */resource/article* protected endpoint and uses Spring Security to secure this service.

```java
@Bean
SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
  http.requestMatchers()
    .antMatchers("/resource/article")
    .and()
    .authorizeRequests()
    .mvcMatchers("/resource/article")
    .access("hasAuthority('SCOPE_message.read')")
    .and()
    .oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt);
  return http.build();
}
```

Please note that the OAuth2 resource service */resource/article* endpoint requires "message.read" permission to access, Spring Security will add "SCOPE_" before the required scope name, so the actual required scope is "message.read" and Not "SCOPE_message.read".

### Build an OAuth2 client with Spring Security

In this section, you will request resource services using the currently recommended WebClient, which is part of Spring's WebFlux package. This is Spring's reactive, non-blocking API, and you can read more about it in the [Spring Documentation](https://docs.spring.io/spring-framework/docs/current/reference/html/web-reactive.html).

Under the CRON task defined by `@Scheduled` this annotation, you will use `WebClient` to make requests.

#### Maven dependencies

```xml
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-web</artifactId>
  <version>2.6.7</version>
</dependency>
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-security</artifactId>
  <version>2.6.7</version>
</dependency>
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-oauth2-client</artifactId>
  <version>2.6.7</version>
</dependency>
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-webflux</artifactId>
  <version>5.3.9</version>
</dependency>
<dependency>
  <groupId>io.projectreactor.netty</groupId>
  <artifactId>reactor-netty</artifactId>
  <version>1.0.9</version>
</dependency>
```

#### Configuration

We will configure OAuth2 authorization information in `application.yml` and specify the OAuth2 client service port number:

```yaml
server:
  port: 8070

spring:
  security:
    oauth2:
      client:
        registration:
          messaging-client-model:
            provider: client-provider
            client-id: relive-client
            client-secret: relive-client
            authorization-grant-type: client_credentials
            client-authentication-method: client_secret_post
            scope: message.read
            client-name: messaging-client-model
        provider:
          client-provider:
            token-uri: http://127.0.0.1:8080/oauth2/token
```

Next we will create a `SecurityConfig` class to configure the beans required by the Spring Security OAuth2 client:

```java
@Bean
SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
  http
    .authorizeRequests(authorizeRequests ->
                       authorizeRequests.anyRequest().permitAll()
                      )
    .oauth2Client(withDefaults());
  return http.build();
}

@Bean
WebClient webClient(OAuth2AuthorizedClientManager authorizedClientManager) {
  ServletOAuth2AuthorizedClientExchangeFilterFunction oauth2Client = new ServletOAuth2AuthorizedClientExchangeFilterFunction(authorizedClientManager);
  return WebClient.builder()
    .filter(oauth2Client)
    .build();
}

@Bean
OAuth2AuthorizedClientManager authorizedClientManager(ClientRegistrationRepository clientRegistrationRepository,
                                                      OAuth2AuthorizedClientService authorizedClientService) {

  OAuth2AuthorizedClientProvider authorizedClientProvider = OAuth2AuthorizedClientProviderBuilder
    .builder()
    .clientCredentials()
    .build();
  AuthorizedClientServiceOAuth2AuthorizedClientManager authorizedClientManager = new AuthorizedClientServiceOAuth2AuthorizedClientManager(clientRegistrationRepository, authorizedClientService);
  authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);

  return authorizedClientManager;
}
```

We create a WebClient instance to perform HTTP requests to the resource server, and add an OAuth2 authorization filter to the WebClient. `AuthorizedClientServiceOAuth2AuthorizedClientManager` This is the high-level controller class that coordinates OAuth2 client credential grant requests, here I will point out that `AuthorizedClientServiceOAuth2AuthorizedClientManager` is a class specifically designed to be used outside the context of an HttpServletRequest .

From the [Spring Documentation](https://docs.spring.io/spring-security/site/docs/5.4.5/reference/html5/#oauth2Client-authorized-manager-provider):

> The DefaultOAuth2AuthorizedClientManager is intended to be used in the context of an HttpServletRequest. When operating outside the context of an HttpServletRequest, use AuthorizedClientServiceOAuth2AuthorizedClientManager instead.

Next we will create a task defined using `@Scheduled` annotation, and inject WebClient to call resource service request:

```java
@Service
public class ArticleJob {

  @Autowired
  private WebClient webClient;

  @Scheduled(cron = "0/2 * * * * ? ")
  public void exchange() {
    List list = this.webClient
      .get()
      .uri("http://127.0.0.1:8090/resource/article")
      .attributes(clientRegistrationId("messaging-client-model"))
      .retrieve()
      .bodyToMono(List.class)
      .block();
    log.info("Call resource server execution result：" + list);
  }
}

```

The client service will initiate a request every 2 seconds and print the result on the console.

### Conclusion

As always, the source code used in this article is available [on GitHub](https://github.com/ReLive27/spring-security-oauth2-sample/tree/main/oauth2-client-model).


You might want to read on to the next one:
- [Authorization Code Flow with Proof Key for Code Exchange (PKCE)](https://dev.to/relive27/authorization-code-flow-with-proof-key-for-code-exchange-pkce-4h22)
- [Spring Security OAuth2 Login](https://dev.to/relive27/spring-security-oauth2-login-51lj)

Thanks for reading!