• 1. An overview of the
  • 2. Introduce the Spring Security OAuth2 dependency
  • 3. Configure the resource server
  • 4. Configure the authorization server
  • 4.1 Authorization Code Mode
  • Spring Security Setting
  • 4.2 Password Mode
  • 4.3 Simplified Mode
  • 4.4 Client Mode
  • 4.5 How to Choose?
  • 4.6 Why do I Have a Client ID and Password
  • 5. Refresh the token
  • 5.1 Obtaining a Refresh token
  • 5.2 “Refresh” access token
  • 5.3 Why is a refresh token needed
  • 6. Delete the token
  • 6.1 Deleting an access token
  • 6.2 Deleting the refresh token
  • 6.3 RFC7009 – OAuth2 Token Revocation
  • 7. Token metadata
  • 666. The eggs

1. An overview of the

In this article, we’ll get started using Spring Security OAuth2.0. Through this article, I hope you have an immersive experience of OAuth2.0.

Also, this is an introductory article, so you’ll need to do some fine-tuning for real world scenarios. Of course, the need for fine tuning, the author will explain in the example, so as not to mislead.

If you are new to OAuth2.0, it is recommended that you read Through Understanding OAuth2.0 by Ruan Yifeng. This article will not cover the OAuth2.0 concept section. Alternatively, you can also take a look at the OAuth 2.0 Minimalist Wizard, a more vivid image.

After reading this article, if you want a deeper understanding of OAuth2.0, read these two books:

  • OAuth2 in Action focuses on principles
  • The OAuth2 2.0 Cookbook is based on Spring Security OAuth2.

After reading this article, if you want to know the source code, you can read xu’s two articles:

  • Re: Spring Security OAuth2 from Scratch (2)
  • Re: Spring Security OAuth2 from Scratch (3)

OK, after a wave of Amway, let’s get into the text together. For Spring Security OAuth2 configuration, there are basically two steps:

  1. Configuring the AuthorizationServer
  2. Configuring resource Servers (ResourceServer)

2. Introduce the Spring Security OAuth2 dependency

In the pom.xml file, the following is introduced:

<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> < version > 1.5.16. RELEASE < / version > < relativePath / > <! -- lookup parent from repository --> </parent> <dependencies> <! -- for Spring MVC --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <! -- for Spring Security --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <! - for the 2.0 - > < the dependency > < groupId > org. Springframework. Security. Request < / groupId > <artifactId>spring-security-oauth2</artifactId> </dependency> </dependencies>Copy the code

Since we use SpringBoot version 1.5.16.RELEASE, we use Spring Security version 4.2.8.RELEASE. Spring Security OAuth2 is available in 2.2.0.15.RELEASE.

3. Configure the resource server

In general, a resource server is an application or service that we provide an API for. For example, order services, goods services. To make the whole example simpler, this article starts by putting it in a Maven project with the authorization server.

① Create a Controller class

Controller */ @restController@requestMapping ("/ API /example") public class ExampleController { @RequestMapping("/hello") public String hello() { return "world"; }}Copy the code
  • Very simply, this is the Controller of a sample module that provides the/API /example/ Hello interface.

② Configure the resource server

/ / resources service Configuration @ Configuration @ EnableResourceServer public class OAuth2ResourceServer extends ResourceServerConfigurerAdapter {@override public void configure(HttpSecurity HTTP) throws Exception {http.authorizerequests () // Enable authentication on "/ API /**" .anyRequest() .authenticated() .and() .requestMatchers() .antMatchers("/api/**"); }}Copy the code
  • The @Configuration annotation ensures that OAuth2ResourceServer can be scanned by SpringBoot for Configuration.
  • @enableresourceserver Comments to enable the resource server.
  • Inheritance (extends) ResourceServerConfigurerAdapter class and override a # configure (HTTP) HttpSecurity method, the configuration of the HTTP request, matching/API / * * “path, Enable authentication verification.

4. Configure the authorization server

In OAuth2.0, four authorization modes are defined:

  • Authorization Code
  • Password mode (Resource owner Password Credentials)
  • Simplified patterns (Implicit)
  • Client credentials

So, I’ve provided an example of a Maven project in springBoot-Labs/Lab-02, either way.

4.1 Authorization Code Mode

The Maven project structure is as follows:

Maven Project Structure

Corresponding GitHub address: github.com/YunaiV/Spri…

1 Configure the authorization server

/ / authorization server Configuration @ Configuration @ EnableAuthorizationServer public class OAuth2AuthorizationServer extends AuthorizationServerConfigurerAdapter { @Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception { clients.inMemory() // <1> // <2> begin ... .withClient(" clientApp "). Secret ("112233") // Client account and password. . RedirectUris (" http://localhost:9001/callback ") / / configure the callback address, optional. .authorizedGrantTypes("authorization_code") // Authorization code schema.scopes ("read_userinfo", "Read_contacts ") // authorized Scope // <2> end... //.and().withClient() // Can continue to configure new Client // <3>; }}Copy the code
  • @ Configuration annotations, ensure OAuth2AuthorizationServer can be SpringBoot scanning to the Configuration.
  • @ EnableAuthorizationServer annotations, open the authorization server.
  • <1>, based on memory, for easy testing. In actual cases, it is better to put them into a database for easy management.
  • <2> creates a Client configuration.
  • At <3>, you can continue adding additional Client configurations using the #and() method.

② Configure login accounts

Create the application.properties file and configure it as follows:

# Spring Security Setting
security.user.name=yunai
security.user.password=1024
Copy the code
  • A login account with the account name “Yunai” and password “1024” has been configured.
  • In the actual production environment, the login data must be stored in the database.

③ Start the project

@SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); }}Copy the code

Start the project

4 Obtain the authorization code

4.1 browser open http://localhost:8080/oauth/authorize? client\_id=clientapp&redirect\_uri=http://localhost:9001/callback&response\_type=code&scope=read\_userinfo

  • Client_id parameter, will pass to our Client in OAuth2AuthorizationServer configuration number.

  • Redirect_url argument, optional, callback address. If the Client corresponding to client_id is not configured with the redirectUris attribute, an error is reported.

  • Response_type parameter, mandatory, returns the authorization code.

  • Scope parameter, optional, scope to apply for authorization. If there are more than one, separate them with commas.

  • The state parameter, optional, indicates the current state of the client. Any value can be specified. The authentication server returns this value unchanged.

  • Not reflected in the above URL

    .

4.2 After the browser is opened, the results are as follows:

The browser

  • Enter the login account “Yunai”/”1024” configured in “② Login Account Configuration”.
  • In actual production, we take QQ tripartite login as an example, as shown below:

  • QQ sample

4.3 Login is successful, select the Scope that allows all applications, and click the [Authorize] button to confirm authorization. The diagram below:

Authorize

4.4 After authorization is complete, the redirect_URI address is called back. As shown below:

The callback address

  • The code parameter is the returned authorization code.

⑤ Get the access token

curl -X POST --user clientapp:112233 http://localhost:8080/oauth/token -H "content-type: application/x-www-form-urlencoded" -d "code=UydkmV&grant_type=authorization_code&redirect_uri=http%3A%2F%2Flocalhost%3A9001%2Fcallback&scope=read_userinfo"
Copy the code
  • – user clientapp: 112233, fill out our configuration in OAuth2AuthorizationServer Client number and password.
  • When code=UydkmV, enter the authorization code obtained in section 4 Obtaining an Authorization Code.

The following is an example of the return result:

{
 "access_token": "e60e41f2-2ad0-4c79-97d5-49af38e5c2e8", 
 "token_type": "bearer", 
 "expires_in": 43199, 
 "scope": "read_userinfo"
}
Copy the code
  • Access_token property, access token. Is not empty.
  • The token_type attribute, the token type, can be “bearer” or “MAC” type. Is not empty.
  • Expires_in attribute, expiration time, in seconds. In general, non-null.
  • Scope property, the scope of permission. If the scope is the same as that applied by the Client, omit this item.
  • The refresh_token property, which refreshes the token, is used to obtain the next access token.
  • In authorization code mode, the permission is null.

To install a curl command, see the “Using curl command under Windows (64-bit)”.

Of course, if you’re using Postman, check out the following two images:

  • Figure 1

  • Figure 2

⑥ Call the resource server API

curl -X GET http://localhost:8080/api/example/hello -H "authorization: Bearer e60e41f2-2ad0-4c79-97d5-49af38e5c2e8"
Copy the code
  • Authorization: Bearer of e60E41F2-2AD0-4C79-97D5-49AF38E5C2E8 with specified access token types and tokens. For example, “Bearer” and “E60E41F2-2AD0-4C79-97D5-49AF38E5C2E8”.

If you are using Postman, check out the following image:

  • figure

4.2 Password Mode

The Maven project structure is as follows:

Maven Project Structure

Corresponding GitHub address: github.com/YunaiV/Spri…

1 Configure the authorization server

/ / authorization server Configuration @ Configuration @ EnableAuthorizationServer public class OAuth2AuthorizationServer extends AuthorizationServerConfigurerAdapter {/ / user authentication @autowired private the AuthenticationManager the AuthenticationManager; @Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { endpoints.authenticationManager(authenticationManager); } @Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception { clients.inMemory() .withClient(" clientApp "). Secret ("112233") // Client account and password. .authorizedGrantTypes("password") // Password mode. Scopes ("read_userinfo", "Read_contacts ") // authorized Scope //.and().withClient() // Can continue to configure new clients; }}Copy the code
  • The Client configuration mode is basically the same as authorization Code mode. The difference is:
  • There is no need to configure the ‘redirectUris’ property because the callback address is not required.
  • Set the authorization mode to Password mode.
  • In addition, you need to introduce AuthenticationManager to support [password mode], Otherwise, “Resolved [error=”unsupported_grant_type”, error_description=”Unsupported grant type: password”]” is reported.

② Configure login accounts

Consistent with authorization Code Mode.

③ Start the project

Consistent with authorization Code Mode.

④ Obtain the access token

curl -X POST --user clientapp:112233 http://localhost:8080/oauth/token -H "accept: application/json" -H "content-type: application/x-www-form-urlencoded" -d "grant_type=password&username=yunai&password=1024&scope=read_userinfo"
Copy the code
  • There is a big difference between authorization Code mode and Authorization Code Mode.
  • Request the OAuth/Token interface directly to obtain the access token.
  • Request parameters with username and password, the user login account and password.
  • Request parameter grant_type is password, indicating [password mode].

The following is an example of the return result:

{
 "access_token": "68de6eb9-5672-4e47-a3e6-110404285ba9",
 "token_type": "bearer",
 "expires_in": 43199,
 "scope": "read_userinfo"
}
Copy the code
  • Consistent with authorization Code Mode.

⑤ Call the resource server API

Consistent with authorization Code Mode.

4.3 Simplified Mode

The Maven project structure is as follows:

Maven Project Structure

Corresponding GitHub address: github.com/YunaiV/Spri…

1 Configure the authorization server

/ / authorization server Configuration @ Configuration @ EnableAuthorizationServer public class OAuth2AuthorizationServer extends AuthorizationServerConfigurerAdapter { @Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception {client.inmemory ().withClient(" clientApp ").secret("112233") // Client account and password. . RedirectUris (" http://localhost:9001/callback ") / / configure the callback address, optional. .authorizedGrantTypes("implicit") // authorization code schema.scopes ("read_userinfo", "Read_contacts ") // authorized Scope //.and().withClient() // Can continue to configure new clients; }}Copy the code
  • Basically the same as [Authorization Code Mode]. The only difference is that the authorization mode is simplified.

FROM Understanding OAuth 2.0

Implicit Grant Type gets its name as an implicit grant type that asks for tokens directly from an authentication server in the browser, bypassing the “authorization code” step. All steps are done in the browser, the token is visible to the visitor, and the client does not require authentication.

② Configure login accounts

Consistent with authorization Code Mode.

③ Start the project

Consistent with authorization Code Mode.

4 Obtain the authorization code

4.1 browser open http://localhost:8080/oauth/authorize? client\_id=clientapp&redirect\_uri=http://localhost:9001/callback&response\_type=implicit&scope=read\_userinfo

  • Basically the same as [Authorization Code Mode]. The difference is simply that the request parameter response_type is “implicit” simplified mode.

4.2 After the browser is opened, the results are as follows:

The browser

  • Basically the same as [Authorization Code Mode], enter the login account “Yunai”/”1024” configured in “② Login Account Configuration”.

4.3 If login succeeds, direct authorization is complete, and the redirect_URI address is recalled. As shown below:

The browser

  • There are two basic differences with [Authorization Code Mode] :
  • After successful login, there is no need to select Scope to allow all applications, and authorization can be completed directly.
  • Instead of an authorization code, an access token is returned.

In general, the Simplified mode is the simplified mode of the authorization code mode.

⑤ Call the resource server API

Consistent with authorization Code Mode.

4.4 Client Mode

The Maven project structure is as follows:

Maven Project Structure

Corresponding GitHub address: github.com/YunaiV/Spri…

1 Configure the authorization server

Consistent with [password mode].

② Configure login accounts

It does not require a login account. Because it has no concept of a user, it interacts directly with the authorization server, using the Client number (client_id) and password (client_secret) to ensure security.

③ Start the project

Consistent with [password mode].

④ Obtain the access token

curl -X POST "http://localhost:8080/oauth/token" --user clientapp:112233 -d "grant_type=client_credentials&scope=read_contacts"
Copy the code
  • Basically the same as [password mode], the differences are as follows:
  • Request parameters do not need to be accompanied by ‘username’ and ‘password’.
  • The request parameter ‘grant_type’ is set to ‘client_credentials’, indicating [password mode].

The following is an example of the return result:

{
 "access_token":"cb2bdfd8-18fa-4b8f-b525-10587bd672e8",
 "token_type":"bearer",
 "expires_in":43199,
 "scope":"read_contacts"
}
Copy the code
  • Consistent with [password mode].

⑤ Call the resource server API

Consistent with [password mode].

In general, [Client mode] is a simplified mode of [password mode].

4.5 How to Choose?

Many fat friends may have the same confusion as the author. The following author quotes a picture of Teacher Yang Bo, I believe it can solve our problems. As shown below:

OAuth2 and Microservices Security Architecture

Authorization Type Selection

Of course, for the yellow box part, for the author or more confused. The author believes that the third-party one-page application SPA is also suitable for the Authorization Code Grant Authorization mode. For example, wechat Web Page Authorization:

Specifically, the web page authorization process is divided into four steps:

1. Direct the user to the authorization page to approve the authorization and obtain the code

Access_token (different from access_token in base support)

3. If necessary, developers can refresh the web license access_token to avoid expiration

4. Access user basic information through web authorization Access_token and OpenID (support UnionID mechanism)

Therefore, the author guesses that Implicit Grant is drawn in the figure because It is recommended to use Implicit Grant in The article “OAuth 2.0 for Client-side Web Applications” by Google.

Of course, it is not clear whether Implicit Grant or Authorization Code Grant Authorization mode should be used. The author prefers to use Authorization Code Grant for third-party client scenarios.

4.6 Why do I Have a Client ID and Password

We see that each of the above four authorization modes passes the Client number and password when the authorization server is finally called. Why is this? With the Client number and password, the authorization server knows where the call came from and whether it was correct. In this way, even if the “bad guys” get Access tokens, they can’t effectively interact with the authorization server without the Client number and password.

5. Refresh the token

In “4. Configuring the Authorization Server,” we never saw the Refresh token we were hoping for. Why is that? Because we did not configure Spring Security OAuth2, we get the access token at the same time we get the refresh token.

So, how do you configure enabling the ability to get refresh tokens? Let’s take a look at “5.1 Getting a refresh token.”

5.1 Obtaining a Refresh token

Because [password mode] is relatively simple, we directly modify the original program. Corresponding GitHub address: github.com/YunaiV/Spri… .

In terms of steps, if they are consistent with the original [password mode], they will be omitted below and marked “consistent with the original”.

1 Configure the authorization server

/ / authorization server Configuration @ Configuration @ EnableAuthorizationServer public class OAuth2AuthorizationServer extends AuthorizationServerConfigurerAdapter {/ / user authentication @autowired private the AuthenticationManager the AuthenticationManager; @Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { endpoints.authenticationManager(authenticationManager); } @Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception { clients.inMemory() .withClient(" clientApp "). Secret ("112233") // Client account and password. .authorizedGrantTypes("password", "refresh_token") // Password mode // <1>. Scopes ("read_userinfo", "Read_contacts ") // authorized Scope //.and().withClient() // Can continue to configure new clients; }}Copy the code
  • At <1>, we magically configured an extra “refresh_token” to enable the ability to get the refresh token. However, there are four authorization modes in OAuth2, so there are “refresh_token” authorization mode. Relax, in Spring Security OAtuh2, “refresh_token” is configured as a special authorization mode to enable obtaining refresh tokens. Therefore, other authorization modes that enable access to refresh tokens require #authorizedGrantTypes(…) When setting, multiple “refresh_token” method arguments are passed.

② Configure login accounts

Same as before.

③ Start the project

Same as before.

④ Obtain the access token

curl -X POST --user clientapp:112233 http://localhost:8080/oauth/token -H "accept: application/json" -H "content-type: application/x-www-form-urlencoded" -d "grant_type=password&username=yunai&password=1024&scope=read_userinfo"
Copy the code
  • Same as before.

The following is an example of the return result:

{
 "access_token":"092a2286-04e7-4e7d-8c20-19fbe25865ff",
 "token_type":"bearer",
 "refresh_token":"afeeb083-997f-4ea8-9334-aab6c1696cca",
 "expires_in":43199,
 "scope":"read_userinfo"
}
Copy the code
  • The “refresh_token” refresh token is returned. The alacrity.

⑤ Call the resource server API

Same as before.

5.2 “Refresh” access token

Because the access access token automatically expires, you can obtain a new access token by using the refresh token. Note that the access token gets the new one, not the old one. That’s why, in the title, I put double quotes around the refresh.

curl -i -X POST -u 'clientapp:112233' http://localhost:8080/oauth/token -H "accept: application/json" -d 'grant_type=refresh_token&refresh_token=afeeb083-997f-4ea8-9334-aab6c1696cca'
Copy the code
  • The call interface is still “oauth/token”, the difference being that the request parameter grant_type passed in is “refresh_token”, using the refresh token.
  • Request parameter refresh_token is the refresh token “AFEEb083-997F-4eA8-9334-aAB6C1696CCA” obtained above.

The following is an example of the return result:

{
 "access_token":"507eb761-4b25-4159-b927-ef3eff5e7eff",
 "token_type":"bearer",
 "refresh_token":"afeeb083-997f-4ea8-9334-aab6c1696cca",
 "expires_in":43199,
 "scope":"read_userinfo"
}
Copy the code
  • The access token obtained is “507EB761-4B25-4159-B927-EF3EFF5e7eff” and is new. Also, the expiration time becomes new.

When I looked at the refresh token of OAuth2.0, I always had a question: does the refresh token have an expiration date? The answer is yes. However, I am not sure that in Spring Security OAuth2, if you do not set the expiration time of the refresh token, the refresh time is infinite. Of course, that doesn’t seem to matter. Because, in the practical use, we definitely need to display (active) set the refresh token expiration time, use ClientBuilder# refreshTokenValiditySeconds (int refreshTokenValiditySeconds) method, The following is an example:

@Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception { clients.inMemory() .withClient(" clientApp "). Secret ("112233") // Client account and password. .authorizedGrantTypes("password", "refresh_token") // Password mode. Scopes ("read_userinfo", "Read_contacts") / / may authorize the Scope refreshTokenValiditySeconds (1200) / 1200 seconds late / /. And (). WithClient () / / can continue to configure the new Client ; }Copy the code

The following is an example of the return result when the refresh token expires:

{
 "error":"invalid_token",
 "error_description":"Invalid refresh token (expired): 7139d075-c4ea-48f0-9dbb-6f65fa6dbeb0"
}
Copy the code
  • If you want to test this effect, you can set the refresh token expiration time to 1 second.

5.3 Why is a refresh token needed

For security reasons, access tokens have a short expiration time and refresh tokens have a long expiration time. In this way, if the access token is stolen, then after a certain period of time, the access token can expire in a short time. Of course, security is also relative. If a new access token is obtained after refreshing the token, the access token may be stolen later.

Also, refreshing the token is optional and may not be returned.

The author sorted out the expiration time of tokens commonly used on open platforms for a better understanding:

  • Xiaomi Open Platform
  • Access Token Lifecycle
  • Access Token: valid for 90 days
  • Refresh Token: Valid for 10 years
  • Wechat open platform
  • Website Application wechat Login Development Guide
  • Access Token: Valid for 2 hours
  • Refresh Token: Indicates an unknown validity period
  • Tencent Open Platform
  • Get Access_Token
  • Access Token: valid for 90 days
  • Refresh Token: Indicates an unknown validity period

6. Delete the token

In fact, at OAuth2, there is a need to delete access tokens and refresh tokens. For example, a user logs out of the system. However, this can be done by deleting the token locally on the client side. However, in order to truly implement token deletion completely, it is necessary for the server itself to delete the token.

In Spring Security OAuth2, there is no built-in interface, so you need to implement it yourself. Spring Security OAuth2 — Simple Token Revocation (Spring Security OAuth2 — Simple Token Revocation)

Because [password mode] is relatively simple, we directly modify the original program. Corresponding GitHub address:. Note that the following is only a Demo, which needs to be modified in the actual production environment.

6.1 Deleting an access token

① Added and deleted the API interface for accessing the token

@Autowired
private ConsumerTokenServices tokenServices;
@RequestMapping(method = RequestMethod.POST, value = "api/access_token/revoke")
public String revokeToken(@RequestParam("token") String token) {
 tokenServices.revokeToken(token);
 return token;
}
Copy the code
  • Delete the access token using the ConsumerTokenServices#revokeToken(String tokenValue) method.

Note that in a real production environment, authorization servers and resource servers are not together, so this is just an example. The main purpose is to introduce the use of the ConsumerTokenServices#revokeToken(String tokenValue) method.

② Access Deletes the API interface that accesses the token.

curl -X POST http://localhost:8080/api/access_token/revoke -H "authorization: Bearer 23874e0b-a1d8-4337-9551-7b9be1ebaebe" -d "token=23874e0b-a1d8-4337-9551-7b9be1ebaebe"
Copy the code

After successful removal, the following error will be reported when using the current access token:

{
 "error":"invalid_token",
 "error_description":"Invalid access token: 23874e0b-a1d8-4337-9551-7b9be1ebaebe"
}
Copy the code

Alternatively, you can refer to github.com/geektime-ge… The implementation of the.

6.2 Deleting the refresh token

① Added and deleted the API interface for accessing the token

@Autowired(required = false) // <1>
private TokenStore tokenStore;
@RequestMapping(method = RequestMethod.POST, value = "api/refresh_token/revoke")
public String revokeRefreshToken(@RequestParam("token") String token) {
 tokenStore.removeRefreshToken(new DefaultOAuth2RefreshToken(token));
 return token;
}
Copy the code
  • The reason required = false is used at <1> is that this example does not show that the TokenStore Bean object is declared to Spring for management, so it cannot be injected. So “6.2 Delete refresh token” is an example that doesn’t work.
  • The important thing is to remove the refresh token by calling the TokenStore#removeRefreshToken(OAuth2RefreshToken Token) method.

② Access and delete the API interface for refreshing the token.

curl -X POST http://localhost:8080/api/refresh_token/revoke -H "authorization: Bearer 52e85411-ac1d-4844-bf03-cf5633e4eecd" -d "token=ead4734a-ca5c-45bf-ac25-9a92291a9fe1"
Copy the code

After successful removal, the following error will be reported when using the current refresh token:

{
 "error":"invalid_token",
 "error_description":"Invalid refresh token: ead4734a-ca5c-45bf-ac25-9a92291a9fe1"
}
Copy the code

Alternatively, you can refer to github.com/geektime-ge… The implementation of the.

6.3 RFC7009 – OAuth2 Token Revocation

In OAuth2, the Token is removed, which is referred to as OAuth2 Token revocation, corresponding to RFC7009. Interested fat friends, can have a look.

OAuth2 Token Revocation (RFC7009 – OAuth2 Token Revocation)

In simple terms, this protocol specifies what API an Authorization Server provides for clients to revoke access_token or refresh_token.

For example, the Client initiates a request as follows:

POST/revoke HTTP / 1.1

Host: server.example.com

Content-Type: application/x-www-form-urlencoded

Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW

token=45ghiukldjahdnhzdauz&token_type_hint=refresh_token

The meanings are as follows:

  1. Revoke: Is the API address provided by the Authorization Server. The Client requests this ADDRESS in Post mode.
  2. Content-type: application/ X-www-form-urlencoded: Fixed this format.
  3. Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW: Authorization document access to protected resources.
  4. Token: Mandatory. The value can be access_token or refresh_token.
  5. Token_type_hint: Optional, indicates the token type. The value can be “access_token” or “refresh_token”.

If the undo succeeds, a response with HTTP Status code 200 is sufficient.

7. Token metadata

FROM OAuth2 Token Metadata (RFC7662-OAuth2 Token Introspection)

To summarize, this specification extends OAuth2 with an API (Introspection Endpoint) that allows third-party clients to query the above information (for example, whether access_token is still valid, who issued it, to whom, Scope and other metadata information).

For example, the Client initiates a request as follows:

POST/introspect HTTP / 1.1

Host: server.example.com

Accept: application/json

Content-Type: application/x-www-form-urlencoded

Authorization: Bearer 23410913-abewfq.123483

token=2YotnFZFEjr1zCsicMWpAA&token_type_hint=access_token

This request is similar to the request to revoke the Token above, with the following implications:

  1. / Introspect: specifies the API address provided by the Authorization Server. The Client requests this ADDRESS in Post mode.
  2. Accept: Application/JSON: The Authorization Server needs to return data in JSON format.
  3. Content-type: application/ X-www-form-urlencoded: Fixed this format.
  4. Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW: Authorization document access to protected resources.
  5. Token: Mandatory. The value can be access_token or refresh_token.
  6. Token_type_hint: Optional, indicates the token type. The value can be “access_token” or “refresh_token”.

If the request is successful, the following message is returned:

 1 {
 2 "active": true,
 3 "client_id": "l238j323ds-23ij4",
 4 "token_type":"access_token",
 5 "username": "jdoe",
 6 "scope": "read write dolphin",
 7 "sub": "Z5O3upPC88QrAjx00dis",
 8 "aud": "https://protected.example.net/resource",
 9 "iss": "https://server.example.com/",
10 "exp": 1419356238,
11 "iat": 1419350238,
12 "nbf": 1419350238,
13 "jti": "abcdefg"
14 "extension_field": "twenty-seven"
15 }
Copy the code

The meanings of the JSON properties are as follows (some of the information is defined in the JSON Web Token, which is described in details in the reference link) :

  1. Active: Mandatory. Indicates whether the token is still valid.
  2. Client_id: Optional. Indicates the Client to which the token belongs. Like the online printing and free shipping site above.
  3. Token_type: optional. Indicates the token type. Corresponding token_type_hint passed.
  4. User_name: optional. The name of the grantor of the token. Like Xiao Ming up there.
  5. Scope: Optional. Corresponding to the optional parameter scope in 5.1.1 Authorization Request, it indicates the scope that the Client is authorized to access, for example, photo albums rather than Logs and other protected resources of Xiaoming.
  6. Sub: Optional. The unique identifier of the owner of the resource to which the token belongs, as defined by JWT. Which is Xiao Ming’s unique identifier.
  7. Aud: Optional. To whom is the token issued? JWT defined.
  8. Iss: Optional. Issuer of token, as defined by JWT.
  9. Exp: Optional. The expiration time of the token, as defined by JWT.
  10. Iat: Optional. The time when ISS issues the token, as defined by JWT.
  11. NBF: Optional. Tokens will not be used before this time, as defined by JWT.
  12. Jti: Optional. The unique identifier of the token, as defined by JWT.
  13. Extension_field: You can extend other related properties by yourself.

Much of this information is optional and can be extended by itself, from which we can solve the problem of access_token’s opacity to clients mentioned above.

We notice that there are a lot of attributes that belong to the JWT definition, so what is this JWT thing? What problem does it solve? If you are interested, check out JSON Web Token (JWT).

The implementation of the token metadata API is not provided here. For those who need it, there are two TokenStore apis:

  • The #readAccessToken(String tokenValue) method reads information about the specified access token.
  • The readRefreshToken(String tokenValue) method reads information about the specified refresh token.

666. The eggs

Note that this article is just an introduction to Spring Security OAuth2. When it comes to actual production and use, there are still a lot of things to do. Such as:

  • Using a relational database, Client and token information is persisted. For example, use JdbcTokenStore.
  • Authorization server and resource server are separated. For example, use RemoteTokenServices.
  • The cache server is used to speed up access to Client and token information. For example, use RedisTokenStore.

Recommended reading articles:

  • CatalpaFlat Spring Security OAuth2
  • Spring Security OAuth2 Development Guide
  • Passport Account Architecture Design for Easily Raising 160 million Registered Users