Securing REST Services With Spring Boot OAuth2

Spring Boot oauth2 example

In this tutorial, we will learn how to build an authorization server in Spring Boot OAuth2 to authenticate your identity and provide access_token which is used in requesting data from server.

This article will explain how to provide security for REST services in Spring Boot. I have explained this article in simple language and with illustrative examples :

What is OAuth 2.0

OAuth 2 is basically an authorization method used for security. It is used to provide access to the secured resources over the HTTP protocol.

OAuuth2 basically enables a third-party application which obtains limited access to an HTTP service :

Whether by allowing that third party application to obtain the access of service on its own behalf
Or on behalf of a resource owner by orchestrating an approval interaction between the resource owner and the HTTP service.

Now let’s understand the roles used in OAuth flow :

Roles

OAuth basically defines below mentioned four roles –

  • Resource Owner : This role is handled by the user of application.
  • Client : Client is the application which user is using and which requires access to user data on the resource server.
  • Resource Server : Resource server are used to store the http services and user data. It stores http services which can return the user’ data to the authenticated clients.
  • Authorization Server : Authorization server is responsible for authenticating the identity of user and also gives an authorization token. The received token is used by resource servers to basically validate your identity.
Spring Boot Oauth2
The flow of OAuth2

Access Token and Refresh Token

An Access token in OAuth2 technology is basically a string value. This string represents the authorization which is issued to the client.

The Tokens in OAuth2 represents some specific scopes and also the access duration. The scope and access durations are granted by the resource owner and Resource server and Authorization servers are responsible for enforcing them.

Refresh token in OAuth2 is issued with the access token to the client. Refresh Token is issued by the authorization server.

This token is basically used for obtaining a new access token in the case when the current access token expires or becomes invalid.

Refresh token can also be used to obtain some additional access tokens with either the identical scope or the narrower scope. Thus, The access tokens may have lesser permission and also a short lifetime compare to as authorized by the resource owner.

At the time of Authorization server discretion , It is optional to issue a refresh token.

Spring Boot OAuth2

The Responsibilities of Access token and Refresh token :

  • Access token is responsible to access data before it gets expired
  • Refresh token is responsible to request for a new access token when the existing access token is expired.

How Spring Boot OAuth2 Technology Works

Let’s understand How OAuth2 technology works with simple scenario based example. The scenario is to do a payment in the store by using credit card.

There are three entities involved :

  • The Store / Web Server.
  • The Bank / Authentication Server.
  • The Buyer / Client.

It is similar in OAuth2 protocol. Below are the steps performed :

The Buyer or Client requests the bank for a Credit Card.

The Bank will request and collects our information.

The Bank verifies the information and provides us a Credit Card if eligibility criteria matches.

In the OAuth2 protocol technology, Authentication Server is the one who grants us the card basis upon our verification.

If Bank gives us the Credit Card, we can go to the Store. In OAuth2 protocol Web Server acts as Store. We present the Card at Web Server.

The store can ask the bank for verification through card reader and also what is the limit of money withdrawal. The Store is the Resource Server here.

The store will then allow us to buy items but only for the permissible amount of money.

Similarly , In the OAuth2 protocol, the Web Server allows us to access pages, depending on our financial status.

Maven dependencies for Spring Security OAuth2

Below is our pom.xml file :

<project xmlns="http://maven.apache.org/POM/4.0.0"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>examples</groupId>
	<artifactId>Spring-Boot-OAuth2</artifactId>
	<version>0.0.1-SNAPSHOT</version>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.4.RELEASE</version>
        <relativePath /> 
    </parent>

	<properties>
		<java.version>1.8</java.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.security.oauth.boot</groupId>
			<artifactId>spring-security-oauth2-autoconfigure</artifactId>
			<version>2.1.8.RELEASE</version>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework.security</groupId>
			<artifactId>spring-security-test</artifactId>
			<scope>test</scope>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>
</project>

Spring Boot OAuth2 – Authorization Server

In the below example, we are creating Spring Boot OAuth2 Authorization server.

We are creating the authorization server using the module of Spring Boot security module – OAuth. The annotation @EnableAuthorizationServer is used to create the authorization server and also we need to inherit the class AuthorizationServerConfigurerAdapter.

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
 
@Configuration
@EnableAuthorizationServer
public class OAuth2AuthorizationServer extends AuthorizationServerConfigurerAdapter 
{
    @Autowired
    private BCryptPasswordEncoder passwordEncoder;
 
    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        security
            .tokenKeyAccess("permitAll()")
            .checkTokenAccess("isAuthenticated()")
            .allowFormAuthenticationForClients();
    }
 
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients
            .inMemory()
            .withClient("clientapp").secret(passwordEncoder.encode("1234"))
            .authorizedGrantTypes("password", "authorization_code", "refresh_token")
            .authorities("READ_ONLY_CLIENT")
            .scopes("read_profile_info")
            .resourceIds("oauth2-resource")
            .redirectUris("http://localhost:8081/login")
            .accessTokenValiditySeconds(120)
            .refreshTokenValiditySeconds(240000);
    }
}

Let’s understand the above example of Spring Boot OAuth2 Authorization server :

Spring Security OAuth module is exposing two endpoints for checking tokens which are /oauth/check_token and /oauth/token_key. These endpoints are by default protected.

The methods tokenKeyAccess() and checkTokenAccess() are basically used for opening these endpoints to use.

In the above example, ClientDetailsServiceConfigurer is basically used for defining an in-memory or the JDBC implementation of the client details service.

The in-memory implementation has following attributes :

AttributePurpose
clientIdIt is the Client Id. It is mandatory.
secretIt is the client secret which is required for trusted clients.
It is optional.
scopeIt defines the client’s scope.
If scope is empty or undefined then the client is not limited
by scope.
authorizedGrantTypesIt defines the Grant types which are authorized to use
for the client.
It’s default value is empty
authoritiesIt defines the authorities which are granted to the client.
These are regular Spring Security authorities.
redirectUrisIt redirects the user-agent to the client’s endpoint.
It must be an absolute URL.

Spring Boot OAuth2 – Resource Server

To create the Spring Boot OAuth2 resource server , we are using annotation @EnableResourceServer and we are also required to extend the class ResourceServerConfigurerAdapter .

import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
 
@Configuration
@EnableResourceServer
public class OAuth2ResourceServer extends ResourceServerConfigurerAdapter 
{
    @Override
    public void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
            .antMatchers("/test/**").authenticated()
            .antMatchers("/").permitAll();
    }
}

We can see that in above security class we have ensured that all the endpoints to be protected should start from /test only. For other endpoints, security is not required . It can be accessed without authentication.

We can also create resource servers which can authenticate users by themselves. In most of the cases, It will be a form based login. See below :

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
 
@Configuration
@Order(1)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
  
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .antMatcher("/**")
                .authorizeRequests()
                .antMatchers("/oauth/authorize**", "/login**", "/error**")
                .permitAll()
            .and()
                .authorizeRequests()
                .anyRequest().authenticated()
            .and()
                .formLogin().permitAll();
    }
  
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth
            .inMemoryAuthentication()
            .withUser("user1").password(passwordEncoder().encode("1234")).roles("USER");
    }
      
    @Bean
    public BCryptPasswordEncoder passwordEncoder(){ 
        return new BCryptPasswordEncoder(); 
    }
}

We can see that above WebSecurityConfigurerAdapter class setup a form based login page. It opens up the all authorization urls with permitAll().

OAuth2 Secured REST resources

In below example of Spring Boot Rest services security using OAuth2 , we have created an API which is returning the logged in user’s name and email.

import org.springframework.http.ResponseEntity;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
 
@Controller
public class RestExample 
{
    @RequestMapping("/test/users/one")
    public ResponseEntity<UserData> data() 
    {
        //some sample data to return for testing
        User user = (User) 
        SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        String email = user.getUsername() + "@techblogstation.com";
 
        UserData data = new UserData();
        data.setName(user.getUsername());
        data.setEmail(email);
 
        return ResponseEntity.ok(data);
    }
}
public class UserData
{
    private String name;
    private String email;
 
    //Setters and getters are omitted
 
    @Override
    public String toString() {
        return "UserData [name=" + name + ", email=" + email + "]";
    }
}

Testing / Demo

We have an API running in the URL http://localhost:8080/test/users/one.

We can access the API by directly putting username and password in login form but third party application cannot access the API as we do in browsers as they require oauth2 token.

Below steps are followed to test the OAuth 2 :

Get authorization grant code from user / client

As displayed in the diagram – “The flow of OAuth2”.

The very first step is ro get the authorization grant from resource owner.

We can get it from URL –  http://localhost:8080/oauth/authorize?client_id=clientapp&response_type=code&scope=read_profile_info

This URL will return a login page. As in the class – SecurityConfig, we have mentioned username and password as user1 and 1234 , we have to use these to login through the page.

OAuth2 login

After successful login, you will be redirected to the page of grant access. In this page, you can choose to grant access to third party application.

Spring Boot OAuth2

After clicking on Authorize, It will redirect the page to a URL like – http://localhost:8081/login?code=ylEpix. Where ‘ ylEpix ‘ is the Authorization code for the third party application.

Get access token from Authorization server

We have already received the authorization code in the previous step. Now the application will use that authorization grant to get the access token.

Now we are required to make the below request. Use the code which is obtained in the previous step.

Below is the data that we need to provide in the request –

 URL - http://localhost:8080/oauth/token

 Headers - 
 Content-Type: application/x-www-form-urlencoded
 authorization: Basic Y2xpZW50YXBwOjEyMzQ1Ng==

 Form data - application/x-www-form-urlencoded

 Form Parameters -

 grant_type=authorization_code
 code=ylEpix
 redirect_uri=http://localhost:8081/login

We are using Google’s REST APIs client to test . We are providing the above mentioned data. See below figures :

Spring Boot OAuth2
OAuth2 Testing

We have received below access token response from above request –

{
"access_token": "1223dfd4-2f87-4e64-ae8c-29ae499377eb",
"token_type": "bearer",
"refresh_token": "9c42ddf7-bdb6-415d-bf02-d083227276ae",
"expires_in": 119,
"scope": "read_profile_info"
} 

Access the user data from resource server

Finally, we can access the user data from the resource server. Hit the following request :

 http://localhost:8080/test/users/one

Below is the Response received :

OAuth2 Results

Conclusion

In this article, we have learnt the Spring Boot OAuth2 technology and How to create the Resource and Authorization server with examples and How to achieve security of Rest Services in Spring Boot using OAuth2.

Leave a Reply

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