0% found this document useful (0 votes)
32 views35 pages

Implement JWT Authentication in A Spring Boot 3 Application - by Eric Cabrel Tiogo - Medium

The document provides a comprehensive guide on implementing JWT authentication in a Spring Boot 3 application, detailing the necessary prerequisites, project setup, and configuration steps. It covers creating user entities, setting up JWT services, and configuring security settings to manage user authentication effectively. The tutorial emphasizes the importance of secure API access and outlines the routes for user registration and authentication.

Uploaded by

ouhssainanouar
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
32 views35 pages

Implement JWT Authentication in A Spring Boot 3 Application - by Eric Cabrel Tiogo - Medium

The document provides a comprehensive guide on implementing JWT authentication in a Spring Boot 3 application, detailing the necessary prerequisites, project setup, and configuration steps. It covers creating user entities, setting up JWT services, and configuring security settings to manage user authentication effectively. The tutorial emphasizes the importance of secure API access and outlines the routes for user registration and authentication.

Uploaded by

ouhssainanouar
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 35

13/05/2025 16:30 Implement JWT authentication in a Spring Boot 3 application | by Eric Cabrel Tiogo | Medium

Implement JWT authentication in a Spring Boot


3 application
15 min read · Mar 19, 2024

Eric Cabrel Tiogo Follow

Listen Share

Photo by Andrea De Santis on Unsplash

In the ever-evolving landscape of web development and application security, the


need for robust authentication mechanisms has never been more critical. When
exposing an API to the public, ensuring only authorized access to the resources is
essential.

https://medium.com/@tericcabrel/implement-jwt-authentication-in-a-spring-boot-3-application-5839e4fd8fac 1/35
13/05/2025 16:30 Implement JWT authentication in a Spring Boot 3 application | by Eric Cabrel Tiogo | Medium

One of the most popular and effective authentication methods in modern web
applications is JSON Web Tokens (JWT). It provides a flexible and stateless way to
verify users' identities and secure API endpoints; it is also called Token-Based
Authentication.

In this article, we will explore the implementation of JWT authentication in a Spring


Boot 3 application.

What we will build


The API must expose routes where some are accessible without authentication
while others require one. Below are the routes:

[POST] /auth/signup → Register a new user

[POST] /auth/login → Authenticate a user

[GET] /users/me → Retrieve the current authenticated user

[GET] /users → Retrieve the current authenticated user

The routes “/auth/signup” and “/auth/login” can be accessed without authentication


while “users/me” and “users” require to be authenticated.

Prerequisites
You must need these tools installed on your computer to follow this tutorial.

JDK 11 or higher — Download link

Maven 3.8 or higher — Download link

MySQL running on Docker — Download’s link

An HTTP client such as Postman, Insomnia, cURL, etc.

We need Docker to run a container for MySQL 8; you can skip it if MySQL is installed
on your computer. Run the command below to start the Docker container from the
MySQL image:

docker run -d -e MYSQL_ROOT_PASSWORD=secret -e MYSQL_DATABASE=taskdb --name mys

 

https://medium.com/@tericcabrel/implement-jwt-authentication-in-a-spring-boot-3-application-5839e4fd8fac 2/35
13/05/2025 16:30 Implement JWT authentication in a Spring Boot 3 application | by Eric Cabrel Tiogo | Medium

Set up the project


The Spring Boot project needs these four dependencies:

The Spring Web: to build Web, including RESTful applications using Spring
MVC. It uses Apache Tomcat as the default embedded container.

The Spring Security: Allows implementing authentication and access-based


control.

The Spring Data JPA: Persist data in SQL stores with Java Persistence API using
Spring Data and Hibernate.

MySQL Driver for Java: The MySQL driver makes it possible to interact with a
database from a Java application.

The Spring Boot online project starter helps us create the project with these
dependencies; go to the URL start.spring.io to generate a new project.

Generate a Spring Boot project with the dependencies.

I chose Java 17 and Maven as the dependency manager, but you can use whatever
you want.

Click on the button “Generate” to download the project, open it in your IDE, and
install the Maven dependencies.

https://medium.com/@tericcabrel/implement-jwt-authentication-in-a-spring-boot-3-application-5839e4fd8fac 3/35
13/05/2025 16:30 Implement JWT authentication in a Spring Boot 3 application | by Eric Cabrel Tiogo | Medium

Configure the database connection


Let’s configure the application to connect to the database and perform database
table creation (using Hibernate under the hood). Open the application configuration
file src/resources/application.properties and add the code below:

server.port=8005

spring.datasource.url=jdbc:mysql://localhost:3307/taskdb?serverTimezone=UTC&all
spring.datasource.username=root
spring.datasource.password=secret

## Hibernate properties
spring.jpa.hibernate.ddl-auto=update
spring.jpa.open-in-view=false

 

Run the application with the command mvn spring-boot:run ; it will start at port
8005.

The Start-up of a Spring Boot application.

If we pay attention to the console when starting the application, we can see the
message displaying a security password generated because Spring Security has the
HTTP Basic authentication enabled by default.

Install JSON Web Token dependencies


https://medium.com/@tericcabrel/implement-jwt-authentication-in-a-spring-boot-3-application-5839e4fd8fac 4/35
13/05/2025 16:30 Implement JWT authentication in a Spring Boot 3 application | by Eric Cabrel Tiogo | Medium

We need a library to encode, decode, and validate the JWT token in the application.
We will use JJWT, so open the “pom.xml” and the code below in the “dependencies”
XML tag:

<dependencies>
<!---- existing dependencies here....... ---->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.11.5</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>0.11.5</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<version>0.11.5</version>
</dependency>
</dependencies>

Save and run mvn install to install the dependencies.

Create the user entity


We perform authentication to ensure the users accessing the system are known,
meaning they are stored in the database.

The first step is to define the user in our system, and it is done by creating a JPA
Entity that will generate the related table in the database. It is recommended to keep
the history of database changes using migrations; I wrote a post about using Flyway
to handle database migrations.

Inside the package entities create a file User.java and add the code below:

package com.tericcabrel.authapi.entities;

import jakarta.persistence.*;
import org.hibernate.annotations.CreationTimestamp;
import org.hibernate.annotations.UpdateTimestamp;

https://medium.com/@tericcabrel/implement-jwt-authentication-in-a-spring-boot-3-application-5839e4fd8fac 5/35
13/05/2025 16:30 Implement JWT authentication in a Spring Boot 3 application | by Eric Cabrel Tiogo | Medium

import java.util.Date;

@Table(name = "users")
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(nullable = false)
private Integer id;

@Column(nullable = false)
private String fullName;

@Column(unique = true, length = 100, nullable = false)


private String email;

@Column(nullable = false)
private String password;

@CreationTimestamp
@Column(updatable = false, name = "created_at")
private Date createdAt;

@UpdateTimestamp
@Column(name = "updated_at")
private Date updatedAt;

// Getters and setters


}

Inside the package repositories , create a file UserRepository.java ; it represents the


Data access layer for the User entity. Add the code below:

package com.tericcabrel.authapi.repositories;

import com.tericcabrel.authapi.entities.User;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;

import java.util.Optional;

@Repository
public interface UserRepository extends CrudRepository<User, Integer> {
Optional<User> findByEmail(String email);
}

https://medium.com/@tericcabrel/implement-jwt-authentication-in-a-spring-boot-3-application-5839e4fd8fac 6/35
13/05/2025 16:30 Implement JWT authentication in a Spring Boot 3 application | by Eric Cabrel Tiogo | Medium

The function findByEmail() will be used later when implementing the user
authentication.

Run the application with the command mvn spring-boot:run ; The table "users" will
be created in the database.

View the user table created with Hibernate.

Extend the User Entity with authentication details


To manage user details related to authentication, Spring Security provides an
interface named “UserDetails” with properties and methods that the User entity
must override the implementation.

Update the file “User.java” to implement the UserDetails interface; below is the code
of the file:

@Table(name = "users")
@Entity
public class User implements UserDetails {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(nullable = false)
private Integer id;

@Column(nullable = false)
private String fullName;

@Column(unique = true, length = 100, nullable = false)


private String email;

https://medium.com/@tericcabrel/implement-jwt-authentication-in-a-spring-boot-3-application-5839e4fd8fac 7/35
13/05/2025 16:30 Implement JWT authentication in a Spring Boot 3 application | by Eric Cabrel Tiogo | Medium

@Column(nullable = false)
private String password;

@CreationTimestamp
@Column(updatable = false, name = "created_at")
private Date createdAt;

@UpdateTimestamp
@Column(name = "updated_at")
private Date updatedAt;

@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return List.of();
}

public String getPassword() {


return password;
}

@Override
public String getUsername() {
return email;
}

@Override
public boolean isAccountNonExpired() {
return true;
}

@Override
public boolean isAccountNonLocked() {
return true;
}

@Override
public boolean isCredentialsNonExpired() {
return true;
}

@Override
public boolean isEnabled() {
return true;
}

// Getters and setters


}

https://medium.com/@tericcabrel/implement-jwt-authentication-in-a-spring-boot-3-application-5839e4fd8fac 8/35
13/05/2025 16:30 Implement JWT authentication in a Spring Boot 3 application | by Eric Cabrel Tiogo | Medium

The method “getAuthorities()” returns the user’s roles list; it is helpful to manage
permissions. We return an empty list because we will not cover role-based access
control.

The method “getUsername()” returns the email address because it is unique


information about the user.

Make sure the method isAccountNonExpired(), isAccountNonLocked(),


isCredentialsNonExpired(), and isEnabled() returns “true”; otherwise, the
authentication will fail. You can customize the logic of these methods to fit your needs.

Create the JWT service


To generate, decode, or validate a JSON Web token, we must expose the related
methods that use the libraries we installed earlier. We will group them into a service
class named JwtService.

Create a package services , then add the file JwtService.java and past the code
below:

package com.tericcabrel.authapi.services;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.io.Decoders;
import io.jsonwebtoken.security.Keys;
import java.security.Key;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Service;

@Service
public class JwtService {
@Value("${security.jwt.secret-key}")
private String secretKey;

@Value("${security.jwt.expiration-time}")
private long jwtExpiration;

public String extractUsername(String token) {


https://medium.com/@tericcabrel/implement-jwt-authentication-in-a-spring-boot-3-application-5839e4fd8fac 9/35
13/05/2025 16:30 Implement JWT authentication in a Spring Boot 3 application | by Eric Cabrel Tiogo | Medium

return extractClaim(token, Claims::getSubject);


}

public <T> T extractClaim(String token, Function<Claims, T> claimsResolver)


final Claims claims = extractAllClaims(token);
return claimsResolver.apply(claims);
}

public String generateToken(UserDetails userDetails) {


return generateToken(new HashMap<>(), userDetails);
}

public String generateToken(Map<String, Object> extraClaims, UserDetails us


return buildToken(extraClaims, userDetails, jwtExpiration);
}

public long getExpirationTime() {


return jwtExpiration;
}

private String buildToken(


Map<String, Object> extraClaims,
UserDetails userDetails,
long expiration
) {
return Jwts
.builder()
.setClaims(extraClaims)
.setSubject(userDetails.getUsername())
.setIssuedAt(new Date(System.currentTimeMillis()))
.setExpiration(new Date(System.currentTimeMillis() + expiration
.signWith(getSignInKey(), SignatureAlgorithm.HS256)
.compact();
}

public boolean isTokenValid(String token, UserDetails userDetails) {


final String username = extractUsername(token);
return (username.equals(userDetails.getUsername())) && !isTokenExpired(
}

private boolean isTokenExpired(String token) {


return extractExpiration(token).before(new Date());
}

private Date extractExpiration(String token) {


return extractClaim(token, Claims::getExpiration);
}

private Claims extractAllClaims(String token) {


return Jwts
.parserBuilder()
.setSigningKey(getSignInKey())
.build()

https://medium.com/@tericcabrel/implement-jwt-authentication-in-a-spring-boot-3-application-5839e4fd8fac 10/35
13/05/2025 16:30 Implement JWT authentication in a Spring Boot 3 application | by Eric Cabrel Tiogo | Medium

.parseClaimsJws(token)
.getBody();
}

private Key getSignInKey() {


byte[] keyBytes = Decoders.BASE64.decode(secretKey);
return Keys.hmacShaKeyFor(keyBytes);
}
}

The methods that will be used are generateToken() , isTokenValid() and


getExpirationTime() .

To generate the JWT token, we need a secret key and the token expiration time;
these values are read from the application configuration properties file using the
annotation @Value.

We must update the application.properties to define these values:

security.jwt.secret-key=3cfa76ef14937c1c0ea519f8fc057a80fcd04a7420f8e8bcd0a7567
# 1h in millisecond
security.jwt.expiration-time=3600000

 

The secret key must be an HMAC hash string of 256 bits; otherwise, the token
generation will throw an error. I used this website to generate one.

The token expiration time is expressed in milliseconds, so remember if your token


expires too soon.

Override the security configuration


By default, the HTTP basic authentication, but we want to override it to perform the:

Perform the authentication by finding the user in our database.

Generate a JWT token when the authentication succeeds.

To override the implementation, let’s create a package configs , add the file
ApplicationConfiguration.java and add the code below:
https://medium.com/@tericcabrel/implement-jwt-authentication-in-a-spring-boot-3-application-5839e4fd8fac 11/35
13/05/2025 16:30 Implement JWT authentication in a Spring Boot 3 application | by Eric Cabrel Tiogo | Medium

package com.tericcabrel.authapi.configs;

import com.tericcabrel.authapi.repositories.UserRepository;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.dao.DaoAuthenticationProvide
import org.springframework.security.config.annotation.authentication.configurat
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

@Configuration
public class ApplicationConfiguration {
private final UserRepository userRepository;

public ApplicationConfiguration(UserRepository userRepository) {


this.userRepository = userRepository;
}

@Bean
UserDetailsService userDetailsService() {
return username -> userRepository.findByEmail(username)
.orElseThrow(() -> new UsernameNotFoundException("User not foun
}

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

@Bean
public AuthenticationManager authenticationManager(AuthenticationConfigurat
return config.getAuthenticationManager();
}

@Bean
AuthenticationProvider authenticationProvider() {
DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider(

authProvider.setUserDetailsService(userDetailsService());
authProvider.setPasswordEncoder(passwordEncoder());

return authProvider;
}
}

 

https://medium.com/@tericcabrel/implement-jwt-authentication-in-a-spring-boot-3-application-5839e4fd8fac 12/35
13/05/2025 16:30 Implement JWT authentication in a Spring Boot 3 application | by Eric Cabrel Tiogo | Medium

The userDetailsService() defines how to retrieve the user using the UserRepository
that is injected.

The passwordEncoder() creates an instance of the BCryptPasswordEncoder() used


to encode the plain user password.

The authenticationProvider() sets the new strategy to perform the authentication.

If you re-run your application at this step, you will not see the password generated
in the console as before. We have successfully overridden the authentication
method.

Create the authentication middleware


For every request, we want to retrieve the JWT token in the header “Authorization”,
and validate it:

If the token is invalid, reject the request if the token is invalid or continues
otherwise.

If the token is valid, extract the username, find the related user in the database,
and set it in the authentication context so you can access it in any application
layer.

In the package configs , create a file JwtAuthenticationFilter.java and add the code
below that implements everything explained previously:

package com.tericcabrel.authapi.configs;

import com.tericcabrel.authapi.services.JwtService;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.lang.NonNull;
import org.springframework.security.authentication.UsernamePasswordAuthenticati
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.authentication.WebAuthenticationDetails
import org.springframework.web.filter.OncePerRequestFilter;
import org.springframework.web.servlet.HandlerExceptionResolver;

https://medium.com/@tericcabrel/implement-jwt-authentication-in-a-spring-boot-3-application-5839e4fd8fac 13/35
13/05/2025 16:30 Implement JWT authentication in a Spring Boot 3 application | by Eric Cabrel Tiogo | Medium

import java.io.IOException;

@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {
private final HandlerExceptionResolver handlerExceptionResolver;

private final JwtService jwtService;


private final UserDetailsService userDetailsService;

public JwtAuthenticationFilter(
JwtService jwtService,
UserDetailsService userDetailsService,
HandlerExceptionResolver handlerExceptionResolver
) {
this.jwtService = jwtService;
this.userDetailsService = userDetailsService;
this.handlerExceptionResolver = handlerExceptionResolver;
}

@Override
protected void doFilterInternal(
@NonNull HttpServletRequest request,
@NonNull HttpServletResponse response,
@NonNull FilterChain filterChain
) throws ServletException, IOException {
final String authHeader = request.getHeader("Authorization");

if (authHeader == null || !authHeader.startsWith("Bearer ")) {


filterChain.doFilter(request, response);
return;
}

try {
final String jwt = authHeader.substring(7);
final String userEmail = jwtService.extractUsername(jwt);

Authentication authentication = SecurityContextHolder.getContext().

if (userEmail != null && authentication == null) {


UserDetails userDetails = this.userDetailsService.loadUserByUse

if (jwtService.isTokenValid(jwt, userDetails)) {
UsernamePasswordAuthenticationToken authToken = new Usernam
userDetails,
null,
userDetails.getAuthorities()
);

authToken.setDetails(new WebAuthenticationDetailsSource().b
SecurityContextHolder.getContext().setAuthentication(authTo
}
}

https://medium.com/@tericcabrel/implement-jwt-authentication-in-a-spring-boot-3-application-5839e4fd8fac 14/35
13/05/2025 16:30 Implement JWT authentication in a Spring Boot 3 application | by Eric Cabrel Tiogo | Medium

filterChain.doFilter(request, response);
} catch (Exception exception) {
handlerExceptionResolver.resolveException(request, response, null,
}
}
}

A try-catch block wraps the logic and uses the HandlerExceptionResolver to forward the
error to the global exception handler. We will see how it can be helpful to do the exception
forwarding.

A great thing to do here is to use caching to find the user by his email address to
improve the performance. I wrote a blog post to show you how to implement
caching in the SpringBoot application.

Configure the application requester filter


The custom authentication is ready, and the remaining thing is to define what
criteria an incoming request must match before being forwarded to application
middleware. We want the following criteria:

There is no need to provide the CSRF token because we will use it.

The request URL path matching /auth/signup and /auth/login doesn't require
authentication.

Any other request URL path must be authenticated.

The request is stateless, meaning every request must be treated as a new one,
even if it comes from the same client or has been received earlier.

Must use the custom authentication provider, and they must be executed before
the authentication middleware.

The CORS configuration must allow only POST and GET requests.

In the package configs , create a file JwtAuthenticationFilter.java and add the code
below:

package com.tericcabrel.authapi.configs;

https://medium.com/@tericcabrel/implement-jwt-authentication-in-a-spring-boot-3-application-5839e4fd8fac 15/35
13/05/2025 16:30 Implement JWT authentication in a Spring Boot 3 application | by Eric Cabrel Tiogo | Medium

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.config.annotation.web.builders.HttpSecurity
import org.springframework.security.config.annotation.web.configuration.EnableW
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenti
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;

import java.util.List;

@Configuration
@EnableWebSecurity
public class SecurityConfiguration {
private final AuthenticationProvider authenticationProvider;
private final JwtAuthenticationFilter jwtAuthenticationFilter;

public SecurityConfiguration(
JwtAuthenticationFilter jwtAuthenticationFilter,
AuthenticationProvider authenticationProvider
) {
this.authenticationProvider = authenticationProvider;
this.jwtAuthenticationFilter = jwtAuthenticationFilter;
}

@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Ex
http.csrf()
.disable()
.authorizeHttpRequests()
.requestMatchers("/auth/**")
.permitAll()
.anyRequest()
.authenticated()
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authenticationProvider(authenticationProvider)
.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthe

return http.build();
}

@Bean
CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();

configuration.setAllowedOrigins(List.of("http://localhost:8005"));
configuration.setAllowedMethods(List.of("GET","POST"));

https://medium.com/@tericcabrel/implement-jwt-authentication-in-a-spring-boot-3-application-5839e4fd8fac 16/35
13/05/2025 16:30 Implement JWT authentication in a Spring Boot 3 application | by Eric Cabrel Tiogo | Medium

configuration.setAllowedHeaders(List.of("Authorization","Content-Type")

UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationS

source.registerCorsConfiguration("/**",configuration);

return source;
}
}

Our authentication is done and ready to be tested.

Create the authentication service


This service will contain the logic for registering a new user and authenticating an
existing user.

Create a new package dtos that will have the DTOs for both actions.

Create the file RegisterUserDto.java and add the code below:

package com.tericcabrel.authapi.dtos;

public class RegisterUserDto {


private String email;

private String password;

private String fullName;

// getters and setters here...


}

Create the file LoginUserDto.java and add the code below:

package com.tericcabrel.authapi.dtos;

public class LoginUserDto {


private String email;

private String password;

https://medium.com/@tericcabrel/implement-jwt-authentication-in-a-spring-boot-3-application-5839e4fd8fac 17/35
13/05/2025 16:30 Implement JWT authentication in a Spring Boot 3 application | by Eric Cabrel Tiogo | Medium

// getters and setters here...


}

We didn’t apply any validation in the DTO for brevity, and if you are interested in
learning how I wrote this complete blog post below to help you:

Validate Request Body and Parameter in Spring Boot


Never trust user input
medium.com

In the package services , create a file AuthenticationService.java and add the code
below:

package com.tericcabrel.authapi.services;

import com.tericcabrel.authapi.dtos.LoginUserDto;
import com.tericcabrel.authapi.dtos.RegisterUserDto;
import com.tericcabrel.authapi.entities.User;
import com.tericcabrel.authapi.repositories.UserRepository;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticati
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

@Service
public class AuthenticationService {
private final UserRepository userRepository;

private final PasswordEncoder passwordEncoder;

private final AuthenticationManager authenticationManager;

public AuthenticationService(
UserRepository userRepository,
AuthenticationManager authenticationManager,
PasswordEncoder passwordEncoder
) {
this.authenticationManager = authenticationManager;
this.userRepository = userRepository;
this.passwordEncoder = passwordEncoder;

https://medium.com/@tericcabrel/implement-jwt-authentication-in-a-spring-boot-3-application-5839e4fd8fac 18/35
13/05/2025 16:30 Implement JWT authentication in a Spring Boot 3 application | by Eric Cabrel Tiogo | Medium

public User signup(RegisterUserDto input) {


User user = new User()
.setFullName(input.getFullName())
.setEmail(input.getEmail())
.setPassword(passwordEncoder.encode(input.getPassword()));

return userRepository.save(user);
}

public User authenticate(LoginUserDto input) {


authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(
input.getEmail(),
input.getPassword()
)
);

return userRepository.findByEmail(input.getEmail())
.orElseThrow();
}
}

Create user registration and authentication routes


We can now create the routes /auth/signup and /auth/login for user registration
and authentication, respectively.

Create a package controllers , add the file AuthenticationController.java and add


the code below:

import com.tericcabrel.authapi.entities.User;
import com.tericcabrel.authapi.dtos.LoginUserDto;
import com.tericcabrel.authapi.dtos.RegisterUserDto;
import com.tericcabrel.authapi.responses.LoginResponse;
import com.tericcabrel.authapi.services.AuthenticationService;
import com.tericcabrel.authapi.services.JwtService;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RequestMapping("/auth")
@RestController
public class AuthenticationController {
https://medium.com/@tericcabrel/implement-jwt-authentication-in-a-spring-boot-3-application-5839e4fd8fac 19/35
13/05/2025 16:30 Implement JWT authentication in a Spring Boot 3 application | by Eric Cabrel Tiogo | Medium

private final JwtService jwtService;

private final AuthenticationService authenticationService;

public AuthenticationController(JwtService jwtService, AuthenticationServic


this.jwtService = jwtService;
this.authenticationService = authenticationService;
}

@PostMapping("/signup")
public ResponseEntity<User> register(@RequestBody RegisterUserDto registerU
User registeredUser = authenticationService.signup(registerUserDto);

return ResponseEntity.ok(registeredUser);
}

@PostMapping("/login")
public ResponseEntity<LoginResponse> authenticate(@RequestBody LoginUserDto
User authenticatedUser = authenticationService.authenticate(loginUserDt

String jwtToken = jwtService.generateToken(authenticatedUser);

LoginResponse loginResponse = new LoginResponse().setToken(jwtToken).se

return ResponseEntity.ok(loginResponse);
}
}

The authentication request returns a LoginReponse instance; below is the code of


that file:

public class LoginResponse {


private String token;

private long expiresIn;

public String getToken() {


return token;
}
 
// Getters and setters...
}

Test the implementation

https://medium.com/@tericcabrel/implement-jwt-authentication-in-a-spring-boot-3-application-5839e4fd8fac 20/35
13/05/2025 16:30 Implement JWT authentication in a Spring Boot 3 application | by Eric Cabrel Tiogo | Medium

Run the application, open an HTTP client, and send a POST request to /auth/signup

with the information in the request body.

Call the API route to register a new user.

Now, let’s try to authenticate with the user we registered. Send a POST request to
/auth/login with the information in the request body.

https://medium.com/@tericcabrel/implement-jwt-authentication-in-a-spring-boot-3-application-5839e4fd8fac 21/35
13/05/2025 16:30 Implement JWT authentication in a Spring Boot 3 application | by Eric Cabrel Tiogo | Medium

Call the API route to authenticate a user and generate the JWT.

Create restricted endpoints to retrieve users


The endpoints /users/me and /users respectively return the authenticated user
from the JWT token provided and the list of all the users.

Create the file UserController.java and add the code below:

package com.tericcabrel.authapi.controllers;

import com.tericcabrel.authapi.entities.User;
import com.tericcabrel.authapi.services.UserService;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RequestMapping("/users")
@RestController
public class UserController {
private final UserService userService;

public UserController(UserService userService) {


this.userService = userService;
}

@GetMapping("/me")
public ResponseEntity<User> authenticatedUser() {
Authentication authentication = SecurityContextHolder.getContext().getA

User currentUser = (User) authentication.getPrincipal();

return ResponseEntity.ok(currentUser);
}

@GetMapping("/")
public ResponseEntity<List<User>> allUsers() {
List <User> users = userService.allUsers();

return ResponseEntity.ok(users);
}
}

 

https://medium.com/@tericcabrel/implement-jwt-authentication-in-a-spring-boot-3-application-5839e4fd8fac 22/35
13/05/2025 16:30 Implement JWT authentication in a Spring Boot 3 application | by Eric Cabrel Tiogo | Medium

In the above code, we retrieve the authenticated user from the security context that
has been set in the file JwtAuthenticationFilter.java at line 68.

we can see the UserService is injected in the controller and provides the function
allUsers() that retrieves the list of users in the database and returns it.

Before testing the implementation, let’s create the UserService.java in the package
services and add the code below:

package com.tericcabrel.authapi.services;

import com.tericcabrel.authapi.entities.User;
import com.tericcabrel.authapi.repositories.UserRepository;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

@Service
public class UserService {
private final UserRepository userRepository;

public UserService(UserRepository userRepository) {


this.userRepository = userRepository;
}

public List<User> allUsers() {


List<User> users = new ArrayList<>();

userRepository.findAll().forEach(users::add);

return users;
}
}

Test the implementation


Re-run the application and follow this scenario:

1. Send a GET request to /users/me and /users , you will get a 403 error

2. Authenticate with POST request at /auth/login and obtain the JWT token.

3. Put the JWT token in the authorization header of the request /users/me and
/users ; you will get an HTTP response code 200 with the data.
https://medium.com/@tericcabrel/implement-jwt-authentication-in-a-spring-boot-3-application-5839e4fd8fac 23/35
13/05/2025 16:30 Implement JWT authentication in a Spring Boot 3 application | by Eric Cabrel Tiogo | Medium

Call the protected API routes using the JWT generated through the login

Customize authentication error messages


The API prevents access from an unauthenticated user or returns a status error
when the authentication credentials aren’t valid. Still, there is no additional message
to give more details to developers consuming the API.

There is no response body when there is an authentication error.


https://medium.com/@tericcabrel/implement-jwt-authentication-in-a-spring-boot-3-application-5839e4fd8fac 24/35
13/05/2025 16:30 Implement JWT authentication in a Spring Boot 3 application | by Eric Cabrel Tiogo | Medium

There are different authentications we want to return a more explicit message. Let’s
enumerates them:

Bad login credentials: thrown by the exception BadCredentialsException, we


must return the HTTP Status code 401.

Account locked: thrown by the exception AccountStatusException, we must


return the HTTP Status code 403.

Not authorized to access a resource: thrown by the exception


AccessDeniedException, we must return the HTTP Status code 403.

Invalid JWT: thrown by the exception SignatureException, we must return the


HTTP Status code 401.

JWT has expired: thrown by the exception ExpiredJwtException, we must return


the HTTP Status code 401.

To handle these errors, we must use the Spring global exception handler to catch the
exception thrown and customize the response to send to the client.

Create a package exceptions then create a file named GlobalExceptionHandler.java

and add the code below:

package com.tericcabrel.authapi.exceptions;

import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.security.SignatureException;
import org.springframework.http.HttpStatusCode;
import org.springframework.http.ProblemDetail;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.authentication.AccountStatusException;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(Exception.class)
public ProblemDetail handleSecurityException(Exception exception) {
ProblemDetail errorDetail = null;

// TODO send this stack trace to an observability tool


exception.printStackTrace();
https://medium.com/@tericcabrel/implement-jwt-authentication-in-a-spring-boot-3-application-5839e4fd8fac 25/35
13/05/2025 16:30 Implement JWT authentication in a Spring Boot 3 application | by Eric Cabrel Tiogo | Medium

if (exception instanceof BadCredentialsException) {


errorDetail = ProblemDetail.forStatusAndDetail(HttpStatusCode.value
errorDetail.setProperty("description", "The username or password is

return errorDetail;
}

if (exception instanceof AccountStatusException) {


errorDetail = ProblemDetail.forStatusAndDetail(HttpStatusCode.value
errorDetail.setProperty("description", "The account is locked");
}

if (exception instanceof AccessDeniedException) {


errorDetail = ProblemDetail.forStatusAndDetail(HttpStatusCode.value
errorDetail.setProperty("description", "You are not authorized to a
}

if (exception instanceof SignatureException) {


errorDetail = ProblemDetail.forStatusAndDetail(HttpStatusCode.value
errorDetail.setProperty("description", "The JWT signature is invali
}

if (exception instanceof ExpiredJwtException) {


errorDetail = ProblemDetail.forStatusAndDetail(HttpStatusCode.value
errorDetail.setProperty("description", "The JWT token has expired")
}

if (errorDetail == null) {
errorDetail = ProblemDetail.forStatusAndDetail(HttpStatusCode.value
errorDetail.setProperty("description", "Unknown internal server err
}

return errorDetail;
}
}

Re-run the application and try to authenticate with invalid credentials, send a
request with an expired JWT or an invalid JWT, etc…

https://medium.com/@tericcabrel/implement-jwt-authentication-in-a-spring-boot-3-application-5839e4fd8fac 26/35
13/05/2025 16:30 Implement JWT authentication in a Spring Boot 3 application | by Eric Cabrel Tiogo | Medium

Authentication errors response returned with detailed information.

The JWT exceptions are caught by the global exception handler because we used the
Handler exception resolver in the file JwtAuthenticationFilter.java to forward them. The
other exceptions come from Spring security.

Wrap up
In this post, we saw how to implement the JSON Web Token authentication in a
Spring Boot application. Here are the main steps of this process:

A JWT authentication filter extracts and validates the token from the request
header.

Whitelist some API routes and protect those requiring a token.

Perform the authentication, generate the JWT, and set an expiration time.

Use the JWT generated to access protected routes.

Catch authentication exceptions to customize the response sent to the client.

With this implementation, you have the basis to protect your API, and you can go a
step further by implementing a Role-Based Access Control (RBAC) following my
tutorial to restrict a resource based on the user role and permission.

https://medium.com/@tericcabrel/implement-jwt-authentication-in-a-spring-boot-3-application-5839e4fd8fac 27/35
13/05/2025 16:30 Implement JWT authentication in a Spring Boot 3 application | by Eric Cabrel Tiogo | Medium

You can find the code source on the GitHub repository.

This post was originally published on https://blog.tericcabrel.com

Please, follow me and share this post if you find it helpful. Subscribe to my
newsletter to get notified when I publish a new post.

Spring Boot Java Authentication Authorization Spring Security

Follow

Written by Eric Cabrel Tiogo


1K followers · 71 following

Software Engineer — Technical Blogger — Open Source enthusiast — Contributor and Mentor at OSS
Cameroon

Responses (57)

Write a response

What are your thoughts?

Heang
Mar 20, 2024

https://medium.com/@tericcabrel/implement-jwt-authentication-in-a-spring-boot-3-application-5839e4fd8fac 28/35
13/05/2025 16:30 Implement JWT authentication in a Spring Boot 3 application | by Eric Cabrel Tiogo | Medium

Your article is very useful and easy to understand. thank you for sharing.

30 Reply

Firman
Apr 14, 2024

Issue Spring Boot v3 or Spring Security 6.x.x 22 2


@Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws…

Dmitriy Gerasimov
Mar 29, 2024

Good job! Just missing JWT renew token when user is authenticated, but token expired or expires in a few
minutes.

11 Reply

See all responses

More from Eric Cabrel Tiogo

https://medium.com/@tericcabrel/implement-jwt-authentication-in-a-spring-boot-3-application-5839e4fd8fac 29/35
13/05/2025 16:30 Implement JWT authentication in a Spring Boot 3 application | by Eric Cabrel Tiogo | Medium

Eric Cabrel Tiogo

Validate Request Body and Parameter in Spring Boot


Never trust user input

Apr 22, 2022 285 4

Eric Cabrel Tiogo

How to copy files over SSH


This post shows how to copy a file from your local computer to a remote server over SSH using
the SCP command and authenticate with an SSH

Apr 4, 2024 146

https://medium.com/@tericcabrel/implement-jwt-authentication-in-a-spring-boot-3-application-5839e4fd8fac 30/35
13/05/2025 16:30 Implement JWT authentication in a Spring Boot 3 application | by Eric Cabrel Tiogo | Medium

Eric Cabrel Tiogo

Implement Role-based Access Control in Spring Boot 3


This post shows how to implement a Role Based Access Control in a Spring Boot 3 application
using Spring Security to ensure only authorized

Mar 19, 2024 292 5

Eric Cabrel Tiogo

Deploy a Spring Boot application with Docker and Nginx Reverse Proxy
Learn how to package a Spring Boot application as a Docker image and deploy it on Virtual
Private Server through a reverse proxy using…

https://medium.com/@tericcabrel/implement-jwt-authentication-in-a-spring-boot-3-application-5839e4fd8fac 31/35
13/05/2025 16:30 Implement JWT authentication in a Spring Boot 3 application | by Eric Cabrel Tiogo | Medium

Oct 30, 2024 25 1

See all from Eric Cabrel Tiogo

Recommended from Medium

In Javarevisited by Mohit Bajaj

How I Optimized a Spring Boot Application to Handle 1M


Requests/Second 🚀
Discover the exact techniques I used to scale a Spring Boot application from handling 50K to
1M requests per second. I’ll share the…

Mar 2 2K 58

https://medium.com/@tericcabrel/implement-jwt-authentication-in-a-spring-boot-3-application-5839e4fd8fac 32/35
13/05/2025 16:30 Implement JWT authentication in a Spring Boot 3 application | by Eric Cabrel Tiogo | Medium

Tanish

FAANG LLD Preparation: Day 2— Mastering the Factory Design Pattern


Welcome to the series of FAANG Low-Level Design (LLD) preparation! Day 2 is here, and if
you’re prepping for system design interviews at…

May 3 4

Ramesh Fadatare

Difference Between @RestControllerAdvice and @ControllerAdvice in


Spring Boot

https://medium.com/@tericcabrel/implement-jwt-authentication-in-a-spring-boot-3-application-5839e4fd8fac 33/35
13/05/2025 16:30 Implement JWT authentication in a Spring Boot 3 application | by Eric Cabrel Tiogo | Medium

Understand the difference between @RestControllerAdvice and @ControllerAdvice in Spring


Boot. Learn when to use them, how they handle…

Mar 8 3

Villy Siu

Authentication with Spring Security, OAuth2 with GitHub and JWT


GitHub Link

Apr 10 2 1

Open in app Sign up Sign in

Search

In Level Up Coding by Zeeshan Adil

https://medium.com/@tericcabrel/implement-jwt-authentication-in-a-spring-boot-3-application-5839e4fd8fac 34/35
13/05/2025 16:30 Implement JWT authentication in a Spring Boot 3 application | by Eric Cabrel Tiogo | Medium

Building Microservices [PART-3]: Role-Based Authentication &


Authorization — Passing Logged-In…
Welcome Back to DevZees ❤

Nov 12, 2024 118

In Dev Genius by The Flying Gibbon

Develop, containerize and run your very first Java Spring Boot app
Spring Boot and Docker made simple: a “super for dummies” guide to creating, testing, and
containerizing an app in just a few steps!

Nov 20, 2024

See more recommendations

https://medium.com/@tericcabrel/implement-jwt-authentication-in-a-spring-boot-3-application-5839e4fd8fac 35/35

You might also like