OAuth2 is an open-standard authorization protocol or framework that provides applications secure designated access. It allows third-party services to access user information without exposing passwords. This tutorial will guide you through the basics of implementing OAuth2 in a Spring Boot application, focusing on setting up an authorization server and securing resources.
Before diving into the implementation, ensure you have the following:
Let's start by creating a new Spring Boot project. You can use Spring Initializr to generate the project structure. Choose the following options:
Download the generated project and import it into your IDE.
The authorization server is responsible for issuing tokens to clients. We'll use Spring Security OAuth2 to set up an authorization server.
Add the following dependencies to your pom.xml:
<dependencies>
<!-- Other dependencies -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security.oauth.boot</groupId>
<artifactId>spring-security-oauth2-autoconfigure</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security.oauth.boot</groupId>
<artifactId>spring-security-oauth2-authorization-server</artifactId>
</dependency>
</dependencies>
Create a configuration class for the authorization server:
package com.example.oauth2demo.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.core.userdetails.UserDetailsService;
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.AuthorizationServerEndpointsConfigurer;
@Configuration
@EnableWebSecurity
public class SecurityConfig extends AuthorizationServerConfigurerAdapter {
private final AuthenticationManager authenticationManager;
private final UserDetailsService userDetailsService;
public SecurityConfig(AuthenticationManager authenticationManager, UserDetailsService userDetailsService) {
this.authenticationManager = authenticationManager;
this.userDetailsService = userDetailsService;
}
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("client")
.secret("{noop}secret")
.authorizedGrantTypes("password", "refresh_token")
.scopes("read", "write");
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.authenticationManager(authenticationManager)
.userDetailsService(userDetailsService);
}
}
Create a user details service to manage user authentication:
package com.example.oauth2demo.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
@Configuration
public class UserDetailsConfig {
@Bean
public UserDetailsService userDetailsService() {
InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
manager.createUser(User.withUsername("user")
.password("{noop}password")
.roles("USER")
.build());
return manager;
}
}
Now, let's secure a REST API using the token issued by the authorization server.
Create a simple REST controller to expose a secured endpoint:
package com.example.oauth2demo.controller;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloController {
@GetMapping("/api/hello")
@PreAuthorize("hasAuthority('SCOPE_read')")
public String sayHello() {
return "Hello, secured world!";
}
}
Create a configuration class for the resource server:
package com.example.oauth2demo.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
@Configuration
@EnableWebSecurity
public class ResourceServerConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/api/**").authenticated()
.and()
.oauth2ResourceServer().jwt();
}
}
To test the setup, you can use tools like Postman or curl.
Use the following curl command to obtain an access token:
curl -X POST http://localhost:8080/oauth/token \
-H "Authorization: Basic Y2xpZW50OnNlY3JldA==" \
-d "grant_type=password&username=user&password=password"
This will return a JSON response with an access token.
Use the obtained access token to access the secured resource:
curl http://localhost:8080/api/hello \
-H "Authorization: Bearer <access_token>"
Replace <access_token> with the actual token you received in the previous step.
This tutorial covered the basics of setting up OAuth2 in a Spring Boot application, including configuring an authorization server and securing resources. By following these steps, you can implement secure authentication and authorization for your applications using OAuth2.