Spring Boot - OAuth2 and JWT
- Transfer

In this article, we will explore the use of OAuth2 and JWT in conjunction with Spring Boot and Spring Security.
Authorization Server
An Authorization Server is the most important component in the Web API security architecture. The authorization server acts as a single authorization point and allows your applications and HTTP endpoints to define the functions of your application.
Resource Server
The authorization server provides clients with an access token to access the HTTP Endpoints of the Resource Server. A resource server is a collection of libraries that contains HTTP Endpoints, static resources, and dynamic web pages.
OAuth2
OAuth2 is an authorization protocol that allows a client (third party) to access the resources of your application. To build an OAuth2 application, we need to know the Grant Type (authorization code), Client ID, and Client secret.
JWT Token
A JWT token is a JSON Web Token. It is used to represent secure identification information (claims) between two parties. For more information about JWT-token you can find on the site www.jwt.io .
We are going to make an OAuth2 application using JWT tokens, which will include an authorization server and a resource server.
First, we need to add the dependencies to our build file.
Maven users can add the following dependencies to
pom.xml.org.springframework.boot spring-boot-starter-jdbc org.springframework.boot spring-boot-starter-security org.springframework.boot spring-boot-starter-web org.springframework.security.oauth spring-security-oauth2 org.springframework.security spring-security-jwt com.h2database h2 org.springframework.boot spring-boot-starter-test test org.springframework.security spring-security-test test Translator's note - for java older than 9, you must also add the following dependencies:
javax.xml.bind jaxb-api 2.3.0 com.sun.xml.bind jaxb-impl 2.2.11 com.sun.xml.bind jaxb-core 2.2.11 Gradle users can add the following dependencies to a file
build.gradle.compile('org.springframework.boot:spring-boot-starter-security')
compile('org.springframework.boot:spring-boot-starter-web')
testCompile('org.springframework.boot:spring-boot-starter-test')
testCompile('org.springframework.security:spring-security-test')
compile("org.springframework.security.oauth:spring-security-oauth2")
compile('org.springframework.security:spring-security-jwt')
compile("org.springframework.boot:spring-boot-starter-jdbc")
compile("com.h2database:h2:1.4.191") Where,
- Spring Boot Starter Security - implements Spring Security
- Spring Security OAuth2 - implements OAUTH2 structures for the operation of the authorization server and resource server.
- Spring Security JWT - Generates JWT Tokens
- Spring Boot Starter JDBC - database access for user verification.
- Spring Boot Starter Web - Provides HTTP Endpoints.
- H2 Database - stores user information for authentication and authorization.
The full file is
pom.xmlgiven below.4.0.0 com.tutorialspoint websecurityapp 0.0.1-SNAPSHOT jar websecurityapp Demo project for Spring Boot org.springframework.boot spring-boot-starter-parent 1.5.9.RELEASE UTF-8 UTF-8 1.8 org.springframework.boot spring-boot-starter-jdbc org.springframework.boot spring-boot-starter-security org.springframework.boot spring-boot-starter-web org.springframework.security.oauth spring-security-oauth2 org.springframework.security spring-security-jwt com.h2database h2 org.springframework.boot spring-boot-starter-test test org.springframework.security spring-security-test test org.springframework.boot spring-boot-maven-plugin Gradle — build.gradle buildscript {
ext {
springBootVersion = '1.5.9.RELEASE'
}
repositories {
mavenCentral()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
}
}
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'org.springframework.boot'
group = 'com.tutorialspoint'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = 1.8
repositories {
mavenCentral()
}
dependencies {
compile('org.springframework.boot:spring-boot-starter-security')
compile('org.springframework.boot:spring-boot-starter-web')
testCompile('org.springframework.boot:spring-boot-starter-test')
testCompile('org.springframework.security:spring-security-test')
compile("org.springframework.security.oauth:spring-security-oauth2")
compile('org.springframework.security:spring-security-jwt')
compile("org.springframework.boot:spring-boot-starter-jdbc")
compile("com.h2database:h2:1.4.191")
}Now add annotations to the main Spring Boot application file
@EnableAuthorizationServerand @EnableResourceServermake the application work both as an authorization server and as a resource server. Also add a simple HTTP Endpoint (/ products) to access the Spring Security-protected API using a JWT token.
package com.tutorialspoint.websecurityapp;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@SpringBootApplication
@EnableAuthorizationServer
@EnableResourceServer
@RestController
public class WebsecurityappApplication {
public static void main(String[] args) {
SpringApplication.run(WebsecurityappApplication.class, args);
}
@RequestMapping(value = "/products")
public String getProductName() {
return "Honey";
}
}Define a POJO class to store user authentication information.
package com.tutorialspoint.websecurityapp;
import java.util.ArrayList;
import java.util.Collection;
import org.springframework.security.core.GrantedAuthority;
public class UserEntity {
private String username;
private String password;
private Collection grantedAuthoritiesList = new ArrayList<>();
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public Collection getGrantedAuthoritiesList() {
return grantedAuthoritiesList;
}
public void setGrantedAuthoritiesList(Collection grantedAuthoritiesList) {
this.grantedAuthoritiesList = grantedAuthoritiesList;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
} Next, for authentication, add the CustomUser class, which extends
org.springframework.security.core.userdetails.User.package com.tutorialspoint.websecurityapp;
import org.springframework.security.core.userdetails.User;
public class CustomUser extends User {
private static final long serialVersionUID = 1L;
public CustomUser(UserEntity user) {
super(user.getUsername(), user.getPassword(), user.getGrantedAuthoritiesList());
}
}Create
@Repository-класс“ROLE_SYSTEMADMIN” to get user information from the database and add rights. This class will also be used in CustomDetailsService.package com.tutorialspoint.websecurityapp;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.stereotype.Repository;
@Repository
public class OAuthDao {
@Autowired
private JdbcTemplate jdbcTemplate;
public UserEntity getUserDetails(String username) {
Collection grantedAuthoritiesList = new ArrayList<>();
String userSQLQuery = "SELECT * FROM USERS WHERE USERNAME=?";
List list = jdbcTemplate.query(userSQLQuery, new String[] { username },
(ResultSet rs, int rowNum) -> {
UserEntity user = new UserEntity();
user.setUsername(username);
user.setPassword(rs.getString("PASSWORD"));
return user;
});
if (list.size() > 0) {
GrantedAuthority grantedAuthority = new SimpleGrantedAuthority("ROLE_SYSTEMADMIN");
grantedAuthoritiesList.add(grantedAuthority);
list.get(0).setGrantedAuthoritiesList(grantedAuthoritiesList);
return list.get(0);
}
return null;
}
} To invoke the DAO repository, you can create your own
UserDetailsServiceby inheriting from org.springframework.security.core.userdetails.UserDetailsService, as shown below.package com.tutorialspoint.websecurityapp;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
@Service
public class CustomDetailsService implements UserDetailsService {
@Autowired
OAuthDao oauthDao;
@Override
public CustomUser loadUserByUsername(final String username) throws UsernameNotFoundException {
UserEntity userEntity = null;
try {
userEntity = oauthDao.getUserDetails(username);
CustomUser customUser = new CustomUser(userEntity);
return customUser;
} catch (Exception e) {
e.printStackTrace();
throw new UsernameNotFoundException("User " + username + " was not found in the database");
}
}
}Next create
@Сonfiguration-классto enable Web Security. Define password encryption parameters ( BCryptPasswordEncoder) and bin in it AuthenticationManager. This class
SecurityConfigurationmust inherit from the class WebSecurityConfigurerAdapter.package com.tutorialspoint.websecurityapp;
import org.springframework.beans.factory.annotation.Autowired;
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.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Autowired
private CustomDetailsService customDetailsService;
@Bean
public PasswordEncoder encoder() {
return new BCryptPasswordEncoder();
}
@Override
@Autowired
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(customDetailsService).passwordEncoder(encoder());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().anyRequest().authenticated().and().sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.NEVER);
}
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring();
}
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}Now add a class to configure OAuth2. In it, define the Client ID, Client Secret, JwtAccessTokenConverter, private and public keys for signing and verifying the token, and also configure
ClientDetailsServiceConfigurerfor valid token scopes.package com.tutorialspoint.websecurityapp;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
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.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;
@Configuration
public class OAuth2Config extends AuthorizationServerConfigurerAdapter {
private String clientid = "tutorialspoint";
private String clientSecret = "my-secret-key";
private String privateKey = "private key";
private String publicKey = "public key";
@Autowired
@Qualifier("authenticationManagerBean")
private AuthenticationManager authenticationManager;
@Bean
public JwtAccessTokenConverter tokenEnhancer() {
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
converter.setSigningKey(privateKey);
converter.setVerifierKey(publicKey);
return converter;
}
@Bean
public JwtTokenStore tokenStore() {
return new JwtTokenStore(tokenEnhancer());
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.authenticationManager(authenticationManager).tokenStore(tokenStore())
.accessTokenConverter(tokenEnhancer());
}
@Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
security.tokenKeyAccess("permitAll()").checkTokenAccess("isAuthenticated()");
}
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory().withClient(clientid).secret(clientSecret).scopes("read", "write")
.authorizedGrantTypes("password", "refresh_token").accessTokenValiditySeconds(20000)
.refreshTokenValiditySeconds(20000);
}
}Now create private and public keys with
openssl. To generate a private key, you can use the following commands -
openssl genrsa -out jwt.pem 2048
openssl rsa -in jwt.pem For public key -
openssl rsa -in jwt.pem -pubout For Spring Boot older than version 1.5, add the
application.propertiesfollowing property to the file (to determine the filtering order of OAuth2 resources).security.oauth2.resource.filter-order=3 If you are using a YAML file, add the following.
security:
oauth2:
resource:
filter-order: 3 Now create the files
schema.sqland data.sqlin classpaththe directory src/main/resources/directoryto connect the application to the H2 database. The file
schema.sqllooks like this:CREATE TABLE USERS (ID INT PRIMARY KEY, USERNAME VARCHAR(45), PASSWORD VARCHAR(60));
Файл data.sql:
INSERT INTO USERS (ID, USERNAME,PASSWORD) VALUES (
1, '[email protected]','$2a$08$fL7u5xcvsZl78su29x1ti.dxI.9rYO8t0q5wk2ROJ.1cdR53bmaVG');
INSERT INTO USERS (ID, USERNAME,PASSWORD) VALUES (
2, '[email protected]','$2a$08$fL7u5xcvsZl78su29x1ti.dxI.9rYO8t0q5wk2ROJ.1cdR53bmaVG'); Note - The password in the database table must be stored in the Bcrypt Encoder format.
You can create an executable JAR file and run the Spring Boot application using the following Maven or Gradle commands.
For Maven, you can use the command below -
mvn clean installAfter “BUILD SUCCESS” you can find the JAR files in the directory
target. For Gradle, you can use the command -
gradle clean buildAfter “BUILD SUCCESSFUL” you can find the JAR files in the directory
build/libs. Now run the JAR file using the command - The
java –jar <JARFILE>application started in Tomcat on port 8080.

Now send a POST request via POSTMAN to receive an OAUTH2 token. Now add the request headers -
http://localhost:8080/oauth/token- Authorization - Basic with your Client Id and Client secret.
- Content-Type - application / x-www-form-urlencoded

And request parameters -
- grant_type = password
- username = your name
- password = your password

Now run and get
access_tokenas shown. 
Now create a request to the resource server API with a Bearer token in the header.

We get the result as shown below.

We are waiting for your comments, and we also inform you that until May 31 you can join the course at a special price.