1. Preface

In [previous post], we talked about how when a third party agrees to an authorization it will call redirectUri to send a return receipt to our server. Our server gets an intermediate authorization credential and authenticates again for the purpose of obtaining a Token. And this logic is responsible by OAuth2LoginAuthenticationProvider, after the analysis of [previous article] we found that the specific logic to obtain Token is done by OAuth2AuthorizationCodeAuthenticationProvider, today we will to make its process clear, to see Spring Security OAuth2 authentication authorization to obtain Token the specific steps.

Note: The OAuth2 related part of this tutorial series is using Spring Security 5.x version.

2. OAuth2AuthorizationCodeAuthenticationProvider

This class is an implementation of AuthenticationProvider for the Authorization Code Grant pattern in OAuth 2.0. A quick note about AuthenticationProvider, it is very important! Be sure to check out the analysis and usage, it is an important entry point for you to extend the channels of authentication methods according to your business.

2.1 OAuth2AccessTokenResponseClient

This implementation contains an OAuth2AccessTokenResponseClient member variable that abstracts the details of obtaining a Token from an authentication server via the tokenUri endpoint. You can implement it according to the four patterns commonly used in OAuth 2.0 to achieve the ability to obtain Token according to different policies.

OAuth2AccessTokenResponseClient

The default configuration for OAuth 2.0 login in Spring Security 5 uses DefaultAuthorizationCodeTokenResponseClient. If you want to use a custom implementation you can configure it via HttpSecurity.

1
2
3
4
5
6
7
8
9
@Override
protected void configure(HttpSecurity http) throws Exception {
    http.oauth2Login()
            .tokenEndpoint()
        // 注入自定义的 OAuth2AccessTokenResponseClient
            .accessTokenResponseClient(authorizationCodeTokenResponseClient);
    // 其它省略

}

Next we look at the logic of getting Token implemented by DefaultAuthorizationCodeTokenResponseClient.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
@Override
public OAuth2AccessTokenResponse getTokenResponse(OAuth2AuthorizationCodeGrantRequest authorizationCodeGrantRequest) {
   Assert.notNull(authorizationCodeGrantRequest, "authorizationCodeGrantRequest cannot be null");
// 1. 封装调用tokenUri所需要的请求参数RequestEntity
   RequestEntity<?> request = this.requestEntityConverter.convert(authorizationCodeGrantRequest);

   ResponseEntity<OAuth2AccessTokenResponse> response;
   try {
   // 2. 通过RestTemplate 发起请求获取 OAuth2AccessTokenResponse
      response = this.restOperations.exchange(request, OAuth2AccessTokenResponse.class);
   } catch (RestClientException ex) {
      OAuth2Error oauth2Error = new OAuth2Error(INVALID_TOKEN_RESPONSE_ERROR_CODE,
            "An error occurred while attempting to retrieve the OAuth 2.0 Access Token Response: " + ex.getMessage(), null);
      throw new OAuth2AuthorizationException(oauth2Error, ex);
   }

  // 3. 解析 ResponseEntity 组织返回值 OAuth2AccessTokenResponse
   OAuth2AccessTokenResponse tokenResponse = response.getBody();

   if (CollectionUtils.isEmpty(tokenResponse.getAccessToken().getScopes())) {

      // originally requested by the client in the Token Request
      tokenResponse = OAuth2AccessTokenResponse.withResponse(tokenResponse)
            .scopes(authorizationCodeGrantRequest.getClientRegistration().getScopes())
            .build();
   }

   return tokenResponse;
}

Three steps.

  1. organize the parameters RequestEntity.
  2. RestOperations to initiate the request.
  3. parse the ResponseEntity to organize the return value.

If some OAuth 2.0 authentication servers get Token in a special way you can implement your own OAuth2AccessTokenResponseClient.

3. Summary

OAuth2AccessTokenResponseClient is the core point of OAuth2AuthorizationCodeAuthenticationProvider. Figure out its role and mechanism will be fine. Here we summarize the OAuth2AuthorizationCodeAuthenticationProvider authentication process.

  1. detect whether the status of the unauthenticated OAuth2AuthorizationCodeAuthenticationToken is legal.
  2. request OAuth 2.0 authentication server to obtain Token and other information through OAuth2AccessTokenResponseClient.
  3. Assemble the authenticated authorization OAuth2AuthorizationCodeAuthenticationToken and return it.

Reference https://felord.cn/oAuth2AuthorizationCodeAuthenticationProvider.html