The New OAuth2 Authorization Server

In this tutorial, I’ll guide you on how to use the new OAuth2 Authorization Server(v0.0.3) built by the Spring Team.

Below are the new features that have been introduced in the newer version:

  1. Enforce one-time use for authorization code
  2. Introduce OAuth2 Tokens
  3. Add Refresh Token grant
  4. Implement Token Revocation Endpoint

OAuth2 is an authorization method to provide access to protected resources over the HTTP protocol.

Access Token vs Refresh Token

Let’s review briefly what is an access token and what is a refresh token.

An access token is a string representing an authorization issued to the client. The access token represents specific scopes and durations of access, granted by the resource owner, and enforced by the resource server and authorization server.

A refresh token is issued (along with an access token) to the client by the authorization server, and it is used to obtain a new access token when the current access token becomes invalid or expires. The refresh token is also used to get additional access tokens with identical or narrower scope (access tokens may have a shorter lifetime and fewer permissions than authorized by the resource owner). Issuing a refresh token is optional at the discretion of the authorization server.

  • The responsibility of the access token is to access data before it gets expired,
  • The responsibility of the refresh token is to request a new access token when the existing access token is expired.

Let’s try it out. I will create an OAuth2 Authorization Server with Spring Authorization Server (0.0.3 version) and Resource Server that needs to be authorized with OAuth2 JWT, based on the example created by the Spring Security team.

Creating Authorization Server Project

I will use Spring Initializer (https://start.spring.io/) to create a new project. When adding new dependencies using the Spring Initializer, you can add the Spring Web dependency only.  The list of needed depdencies I will add a little bit later.

After creating a project from Spring Initializer import the project into Eclipse.

Dependencies in the pom.xml file

Below is a list of dependencies in my pom.xml file. Notice the dependency for the new OAuth2 Authorization Server. The new authorization server is still in the experimental phase and the latest version at the time of writing this blog post is only 0.0.3.

<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.security.experimental</groupId>
            <artifactId>spring-security-oauth2-authorization-server</artifactId>
            <version>0.0.3</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
</dependencies>

Adding the Authorization Server Config

The ProjectConfig class below is used to define an in-memory or JDBC implementation of the client details service. I have used in-memory implementation. It has the following important attributes:

  • clientId – (required) the OAuth2 Client Id,
  • secret – (required for trusted clients) the client secret, if any,
    scope – The scope to which the client is limited. If the scope is undefined or empty (the default), the client is not limited by scope,
    authorizedGrantTypes – Grant types that are authorized for the client to use. The default value is empty,
    authorities – Authorities that are granted to the client (regular Spring Security authorities),
    redirect URIs – redirects the user-agent to the client’s redirection endpoint. It must be an absolute URL.

For building Authorization Server with the Spring Authorization Server, I will create a config for Spring Security, which will also create the config WebSecurityConfigurerAdapter just like Spring Security usually uses apply default configuration to configure Spring Security’s various endpoints that are required for this. Authorization Server using the OAuth2 protocol.

Create a registeredClientRepository bean that comes with the Spring Authorization Server to use as the client’s information to authorize the system. It can be seen that the value of Client Id was fixed to messaging-client and Client Secret to, secret making the example work only for one Client and store data in the memory of the system.

Create a keySource bean to manage system keys, this version has only one implementation StaticKeyGeneratingKeyManager (it will be replaced by CryptoKey in the future, it should be more secure).

Finally, the UserDetailsService just like normal Spring Security which uses Spring Security in general, for storing user data and storing it in memory as well.

import java.time.Duration;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.OAuth2AuthorizationServerConfiguration;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.keys.KeyManager;
import org.springframework.security.crypto.keys.StaticKeyGeneratingKeyManager;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.core.AuthorizationGrantType;
import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
import org.springframework.security.oauth2.server.authorization.client.InMemoryRegisteredClientRepository;
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;

@Configuration
@EnableWebSecurity
@Import(OAuth2AuthorizationServerConfiguration.class)
public class ProjectConfig extends WebSecurityConfigurerAdapter {

    @Bean
    public UserDetailsService userDetailsService() {
        var uds = new InMemoryUserDetailsManager();

        var u1 = User.withUsername("test").password("12345").authorities("read").build();

        uds.createUser(u1);

        return uds;
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return NoOpPasswordEncoder.getInstance();
    }

    @Bean
    public RegisteredClientRepository registeredClientRepository() {
        var rc = RegisteredClient.withId("client").clientId("client1").clientSecret("secret1")
                .clientAuthenticationMethod(ClientAuthenticationMethod.BASIC)
                .authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
                .authorizationGrantType(AuthorizationGrantType.REFRESH_TOKEN)
                .redirectUri("http://localhost:8080/authorized").tokenSettings(t -> {
                    t.enableRefreshTokens(true);
                    t.reuseRefreshTokens(true);
                    t.accessTokenTimeToLive(Duration.ofHours(5));
                }).scope("read").build();

        return new InMemoryRegisteredClientRepository(rc);
    }

    @Bean
    public KeyManager keyManager() {
        return new StaticKeyGeneratingKeyManager();
    }
}

The basic configuration of our OAuth2 Authorization Server is now ready. We should be able to build and run it on default port 8080.

Running the Authorization Server

You should be able to run the new OAuth2 Authorization Server like any other Spring Boot application. You can run it from your Eclipse development environment or using the below maven commands.

Running authorization server using Maven commands

mvn clean package
mvn spring-boot:run

Running Server using Eclipse IDE

Notice, that the authorization server has started on default port 8080. This is because I have not configured any other port for it in the application.properties file.

The log shows the filters used with the endpoints for the OAuth2 protocol as follows:

  • POST /oauth2/token — as a token endpoint,
  • POST /oauth2/authorize — as Authorization endpoint,
  • GET /oauth2/authorize — It is also an Authorization endpoint,
  • POST /oauth2/revoke — as a token revoke endpoint,
  • GET /oauth2/jwks — It is a JWT key endpoint.

The Authorization endpoint can either use the HTTP method POST or GET.

Getting Access Token and Refresh Token

To try how the server works and get it to issue us a JWT Access Token and a Refresh token, I will use Postman HTTP Client.

To acquire an access token I will use the Authorization Code grant type, and there are two main steps that I will need to do.

  1. Authenticate and get the OAuth2 Code,
  2. Exchange the OAuth Code for an Access token and Refresh token.

Getting the OAuth2 Code

To authenticate user and get the value of OAuth2 Code, open the following URL in the browser window.

http://localhost:8080/oauth2/authorize?response_type=code&client_id=client1&scope=read

Where:

  • http://localhost:8080 – is the domain and port number on which the OAuth2 Authorization Server is running,
  • /oauth2/authorize – is the authorization endpoint,
  • ?response_type=code – a required parameter to get the authorization code back,
  • &client_id=client1 – the OAuth2 Client Id that we have configured in the Authorization Server when registering the OAuth2 client. To review this, have a look at the ProjectConfig Java class above.
  • &scope=read – Scope.

Once you open the above URL in the browser window, you should be redirected to the user authentication page. Provide the username and password, that are configured in the userDetailsService() method in the ProjectConfig Java class above.

If the user authentication is successful, the authorization server will generate the authorization code, will attach it to the Redirect URI and will redirect the browser to the Redirect URI with the code request parameter attached to the URL.

Once the redirect takes place, check the URL in the browser address bar. The Redirect URI will look similar to the one below.

http://localhost:8080/authorized?code=5LTawRGAB2ZbjO9x6zE-KkN6xEYSFHV3qn73HyDinxbRDwrwx0juVuT-XSXhrO9yXYMMtTUDi8K_2K3GbOjgs4zCUV44nfauhMQOYcxucDqTcUxVZPmST2bEzgNRdu9R

Where

  • code – is the URL query string parameter that hold the value of OAuth2 code that will need to be used in the following step. We will exchange this code for an access token.

Exchange OAuth2 Code for an Access Token

To exchange the above OAuth2 Code value for an access token, we will need to use Postman HTTP client to sent HTTP Post request to a /oauth2/token endpoint. The details of HTTP request are below.

1. Configure Basic Auth

A request to /oauth2/token endpoint will need to contain the “Basic Auth” credentials.

In the Postman HTTP client, open the Authorization tab and configure the Basic OAuth as it is shown in the image below.

  1. Set Authrozation Type to Basic Auth,
  2. Provide username and password. These values are the OAuth2 ClientID and Client Secret that we have configured in the registeredClientRepository() method of the ProjectConfig Java class above.

2. Configure Request Parameters

To exchange the OAuth2 code for an access token, we will need to send HTTP Post request to the /oauth2/token endpoint.

  • http://localhost:8080/oauth2/token

There are two request parameters that will need to attach to this request:

  • ?grant_type=authorization_code
  • &code=5LTawRGAB2ZbjO9x6zE-KkN6xEYSFHV3qn73HyDinxbRDwrwx0juVuT-XSXhrO9yXYMMtTUDi8K_2K3GbOjgs4zCUV44nfauhMQOYcxucDqTcUxVZPmST2bEzgNRdu9R

Below is a screenshot of my Postman HTTP Client with the request details. If the request is successful, you should get back the JSON response containing Access Token and Refresh token as it is shown on the image below as well.

Using Refresh Token

Access Tokens are short-lived and they expire. Once the accesss token has expired, you can use the Refresh Token to get a new value of Access Token. To do that, you will need to send HTTP Post request to the same /oauth2/token endpoint providing the following request paramters.

  • ?grant_type=refresh_token
  • &refresh_token=MdhBcCUQh9b-nTBJAKTieW_7_rFGPHWPI0qiw9upY48sJklm_j-r8KhUc0LT0uQoEkyBLUM5oRo376zudAjhzSwTulG0qIKs0hpiRgHRiI4YhXCkFRheCNMb5zhjqmAp

Notice that to request for a new access token, the Grant Type request parameter is now different. When using Refresh Token to get a new value of an Access Token, the Grant Type request parameter must be set to refresh_token.

Below is a screenshot of Postman HTTP Client with request details to aquire a new access token.

I hope this tutorial was of some value to you.

To learn more about OAuth2 and how to use OAuth2 in Spring Boot applications, please check the following video course – “OAuth2 in Spring Boot Applications

OAuth2 in Spring Boot Applications
OAuth2 in Spring Boot Applications

Happy learning!

Leave a Reply

Your email address will not be published. Required fields are marked *

Free Video Lessons

Enter your email and stay on top of things,

Subscribe!