Spring Boot Application with OAuth2 Security

Conor O'Dwyer
10 min readSep 20, 2020

In this tutorial I will show you how to create a Spring Boot application and implement OAuth security to secure your resource endpoints. In part 1 the resource endpoint will return a simple response message, in part 2 I will cover connecting your Spring Boot application to a SQL database to return data from your endpoints.

1. Environment Setup

If you do not already have Java and Maven installed, you will first need to install them. I will use IntelliJ IDEA as the IDE for this tutorial, but you can use Eclipse or your preferred IDE instead. If you already have your environment setup, you can skip to section 2.

The JDK can be downloaded here. Once you have installed it, you will need to set the JAVA_HOME system variable in your environment variables to the jdk folder in your install location and add %JAVA_HOME% to the Path system variable.

Maven can be downloaded here, select the source zip file. Once you have it downloaded, you will need to unzip the file and set the M2_HOME system variable in your environment variables to the bin directory in the extracted folder. Add %M2_HOME% to the Path system variable.

If you do not have an IDE already installed. IntelliJ IDEA Community Edition can be downloaded from here.

2. Create a Project

The first step is to create your Maven project. In IntelliJ IDEA, select File > New > Project. Select Maven as your project type, ensure you have the Project SDK selected as your Java JDK and click Next. Give your project a name, such as ‘SimpleSpringApp’, choose the location to create your project and click Finish. It may take a minute or two to initialise your project.

Once the project is created, we need to open the pom.xml file to add our Spring dependencies. Add the following to your pom.xml file. After updating your pom.xml file you will need to refresh your project so that the new dependencies can be resolved; right click on your SimpleSpringApp root folder, select Maven > Reimport.

Note: I have also added a dependency for Lombok which I will use in this tutorial.

<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.3.RELEASE</version>
</parent>

<dependencies>
<!-- Spring -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>${spring.boot.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.security.oauth</groupId>
<artifactId>spring-security-oauth2</artifactId>
<version>${springoauth2.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>${springsecurity.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
<version>2.0.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
<version>${springsecurity.version}</version>
</dependency>
<!-- Lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</dependency>
</dependencies>

<properties>
<springsecurity.version>4.2.1.RELEASE</springsecurity.version>
<springoauth2.version>2.0.3.RELEASE</springoauth2.version>
<spring.boot.version>2.0.3.RELEASE</spring.boot.version>
<java.version>1.8</java.version>
<lombok.version>1.18.2</lombok.version>
</properties>

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

Now we need to create a package name under our src > main > java folder of our project. You can do this by right-clicking on the java folder and selecting New > Package. I gave my package the name ‘com.example’. We will then create a Java Class under this package called ‘WebApplication’ which will be the main class to run our Spring Boot application. Your project folder should be as shown below.

Add the following code to your WebApplication class. The @SpringBootApplication annotation is equivalent to adding the @Configuration, @EnableAutoConfiguration and @ComponentScan annotations to your class which allows for much of the required Spring configuration to be done automatically and the package to be scanned for other components and extra beans and configuration classes to be added.

We will be configuring the DataSource ourselves later in the tutorial, so the @EnableAutoConfiguration(exclude={DataSourceAutoConfiguration.class}) annotation is added to exclude the auto-configuration of our DataSource.

Extending the SpringBootServletInitializer class allows the WebApplication class to be registered as a configuration class, the main method of which simply runs the Spring application.

@EnableAutoConfiguration(exclude={DataSourceAutoConfiguration.class})
@SpringBootApplication
public class WebApplication extends SpringBootServletInitializer {

public static void main(String[] args) {

SpringApplication.run(WebApplication.class, args);
}
}

At this point we can run our Spring Boot application. In the top right of the IntelliJ window, click on Add Configuration. Click on the + icon and select Maven to create a new configuration. Name your configuration ‘Spring Boot’, set the Working directory to your project folder and enter ‘spring-boot:run’ in the Command line section.

Click OK to create your run configuration. Click on the green play button next to your configuration name to run your Spring Boot application. In the Run window, you should see ‘Started WebApplication in x seconds’ to indicate your application is running successfully. Right now your application doesn’t do much, so we can stop the application and set up the rest of our project.

3. Configuration Classes

The next thing we want to do is create a sub-package under our com.example package with the name ‘config’. We will then create 3 Java classes in this package called, AuthorizationServerConfig, ResourceServerConfig and WebSecurityConfig.

The first class we will look at is AuthorizationServerConfig. The @Configuration and @EnableAuthorizationServer annotations need to be added to the class and it must extend the AuthorizationServerConfigurerAdapter class.

We will then override the ClientDetailsServiceConfigurer as shown below. The client_id, client_secret and SimpleSpringScope are values that are configured for your Spring app and must be provided during authentication; you can choose whatever values you like. The grant type of password means that we will provide the user’s username and password when authenticating to get our access token. The grant type of refresh_token means that we will also get a refresh token with our access token which can then be used for future authentication instead of the username and password.

@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("client_id")
.secret("client_secret")
.authorizedGrantTypes("password", "refresh_token")
.scopes("SimpleSpringScope")
.accessTokenValiditySeconds(60*15) // 15 mins
.refreshTokenValiditySeconds(60*60); // 60 mins
}

We must also configure our AuthenticationManager in the AuthorizationServerConfig class, which is done as shown.

private final AuthenticationManager authenticationManager;

@Autowired
public AuthorizationServerConfig(AuthenticationManager authenticationManager) {
this.authenticationManager = authenticationManager;
}

The last thing we need to do in this class is override the AuthorizationServerEndpointsConfigurer as shown. We use the @Autowired annotation to import the TokenStore and UserApprovalHandler which will be configured elsewhere in our application.

@Autowired
private TokenStore tokenStore;
@Autowired
private UserApprovalHandler userApprovalHandler;
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.tokenStore(tokenStore).userApprovalHandler(userApprovalHandler).authenticationManager(authenticationManager);
}

Your final class should look like this:

We will now move onto the ResourceServerConfig class. The @Configuration and @EnableResourceServer annotations need to be added to the class and it must extend the ResourceServerConfigurerAdapter class.

We will then override the HttpSecurity as shown below. With this configuration we are authorizing access to endpoints (which we will create later) when the user has the “USER” role. Additional configuration could be implemented here to allow different user roles access to different endpoints, but I have kept it simple for this tutorial.

@Override
public void configure(HttpSecurity http) throws Exception {
http.anonymous().disable()
.requestMatchers().antMatchers("/api/**")
.and().authorizeRequests()
.antMatchers("/api/**")
.hasRole("USER");
}

Your final class should look like this:

The last part of the Spring configuration is the WebSecurityConfig class. The @Configuration, @EnableWebSecurity and @EnableGlobalMethodSecurity(prePostEnabled = true) annotations need to be added to the class and it must extend the WebSecurityConfigurerAdapter class.

As we did for the ResourceServerConfig class, we want to override the HttpSecurity for our WebSecurityConfig class as shown below. In this case we are permitting calls to the /oauth/token endpoint which is used for authentication. We are also disabling cross-site request forgery (csrf) for our application.

@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.antMatchers("/oauth/token").permitAll()
.anyRequest().authenticated();
}

We then need to configure the authentication for our application. In this example we are going to create an in-memory user with a username of “user”, password of “password” and role “USER”. You can add as many users as you want here. In real applications you will likely not create in-memory users in this way and instead configure the authentication using the UserDetailsService to link to users stored in your database, however, I am keeping it simple for this tutorial. We are also creating Beans for password encryption (using BCryptPasswordEncoder) and AuthenticationManager.

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("user")
.password("password")
.roles("USER");
}

@Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}

@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}

Now that we have the authentication configured, we need to configure our TokenStore. Note: Remember that we disabled the DataSourceAutoConfiguration in our WebApplication class.

As we did with our users, we are going to store our access tokens in-memory. The configuration is shown below. We are autowiring the ClientDetailsService that we configured in our AuthorizationServerConfig class. The disadvantage to storing access tokens in-memory is that if you need to restart your application, any previously authenticated tokens will become invalid. In real applications we would therefore usually configure a DataSource with a SQL database and specify this in our TokenStore. I will not be covering that setup in this tutorial.

@Autowired
private ClientDetailsService clientDetailsService;
@Bean
public TokenStore tokenStore() {
return new InMemoryTokenStore();
}

@Bean
@Autowired
public TokenStoreUserApprovalHandler userApprovalHandler(TokenStore tokenStore) {
TokenStoreUserApprovalHandler handler = new TokenStoreUserApprovalHandler();
handler.setTokenStore(tokenStore);
handler.setRequestFactory(new DefaultOAuth2RequestFactory(clientDetailsService));
handler.setClientDetailsService(clientDetailsService);
return handler;
}

@Bean
@Autowired
public ApprovalStore approvalStore(TokenStore tokenStore) throws Exception {
TokenApprovalStore store = new TokenApprovalStore();
store.setTokenStore(tokenStore);
return store;
}

Your final class should look like this:

4. Create Resource

Now that we have configured our Spring Boot application, we can create an endpoint which returns a response message to an authenticated user. Before we can create our endpoint, we need to define the Response object that will be returned by the endpoint. As we did with the ‘config’ sub-package, we will create another sub-package called ‘domain’. Within this package, create a Java class called ‘Response’.

Add the following code to your Response class. The Response class is a simple object that has a status, data and message which will be returned from our endpoint. The @Data and @Builder annotations are part of Lombok (which we added as a dependency in our pom.xml file). The @Data annotation auto-creates the getters and setters, and the ToString and EqualsAndHasCode methods without needing to define them in our class. The @Builder annotation allows us to easily create an instance of our class as will be shown when we configure our endpoint.

@Data
@Builder
public class Response {
private String status;
private String data;
private String message;
}

Now that we have our Response object defined, we will create another sub-package called ‘controller’. Within this package, create a Java class called ‘ResponseController’, which is where we will define our endpoint.

Add the following code to the ResponseController class. The @RestController annotation indicates to Spring that this class contains resource endpoints defined. The @RequestMapping annotation specifies that the endpoints within this class can accept any request format and will return json as the response format. This can be configured for each endpoint within the class individually or for the entire class as I have done here. The class contains a single method called checkResponse. The @GetMapping annotation means that this method is called when a GET request is made to the ‘/api/checkResponse’ endpoint. The method returns the Response which is built using the Lombok Builder.

Note: the endpoint address begins with ‘/api/’ as we configured the ResourceServer to provide access to users with the “USER” role to any resources located at ‘/api/**’ endpoints.

@RestController
@RequestMapping(consumes = "*", produces = "application/json")
public class ResponseController {

@GetMapping(value = "/api/checkResponse")
Response checkResponse() {
return Response.builder()
.status("success")
.data("test data")
.message("endpoint successfully called")
.build();
}
}

You are now ready to test your application.

5. Test your Spring Boot app

We will be using Postman to test our application. Using the Spring Boot run configuration in IntelliJ we created earlier, run your application. Your application will be available at http://localhost:8080.

The first thing we need to do is authenticate our user to get an access token by sending a POST request to the /oauth/token endpoint. In Postman, set the Authorization type to Basic Auth and enter your client_id and client_secret as username and password.

You then need to add the Body of the request. The body type will be x-www-form-urlencoded and your will need to enter the grant_type of password and the username, password and scope that your AuthorizationServerConfig class.

Click Send in Postman to send the authentication request to your app. You should get a successful response containing your access_token which can be used for requests to your resource endpoints.

Copy the access_token value from the response. Create a new GET request to the /api/checkResponse endpoint with Authorization type of Bearer Token and add your access_token as the Token. Select ‘none’ as the Body since we don’t need to send any body with our GET request. Click Send to see the expected Response object that we configured for our endpoint.

6. Conclusion

You have now successfully configured a simple Spring Boot application with OAuth2 security. In the next part I will cover how to connect your Spring Boot application to your SQL database for user management, token storage and returning useful data from your endpoints.

--

--