Learn to implement JWT Authentication with Spring Security 6. Learn about token creation, validation, filters, securing APIs using modern best practices.
๐ What is JWT Authentication?
JWT (JSON Web Token) is a stateless, compact, and secure mechanism for transmitting user authentication data between parties.
A JWT typically consists of three parts:
header.payload.signature
When a user logs in:
- A JWT is issued and sent to the client.
- For every secured request, the client includes this token in the
Authorizationheader. - The server validates the token and grants access accordingly.

๐งฉ Project Structure
com.kscodes.springboot.security.jwt
โโโ config/
โ โโโ SecurityConfig.java
โโโ controller/
โ โโโ AuthController.java
โโโ filter/
โ โโโ JwtAuthenticationFilter.java
โโโ model/
โ โโโ AuthRequest.java
โโโ service/
โ โโโ JwtService.java
โโโ SpringBootJwtApplication.java
๐ฆ Maven Dependencies
In pom.xml:
org.springframework.boot
spring-boot-starter-security
org.springframework.boot
spring-boot-starter-web
io.jsonwebtoken
jjwt-api
0.11.5
io.jsonwebtoken
jjwt-impl
0.11.5
runtime
io.jsonwebtoken
jjwt-jackson
0.11.5
runtime
๐ Security Configuration
SecurityConfig.java
package com.kscodes.springboot.security.jwt.config;
import com.kscodes.springboot.security.jwt.filter.JwtAuthenticationFilter;
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.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
@Configuration
public class SecurityConfig {
private final JwtAuthenticationFilter jwtAuthFilter;
public SecurityConfig(JwtAuthenticationFilter jwtAuthFilter) {
this.jwtAuthFilter = jwtAuthFilter;
}
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/auth/**").permitAll()
.anyRequest().authenticated()
)
.addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class);
return http.build();
}
@Bean
public UserDetailsService userDetailsService() {
return new InMemoryUserDetailsManager(
User.withUsername("user")
.password(passwordEncoder().encode("password"))
.roles("USER")
.build()
);
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public AuthenticationManager authenticationManager(AuthenticationConfiguration config) throws Exception {
return config.getAuthenticationManager();
}
}
๐งช Auth Request DTO
AuthRequest.java
package com.kscodes.springboot.security.jwt.model;
public class AuthRequest {
private String username;
private String password;
// Getters and setters
}
๐ JWT Service
JwtService.java
package com.kscodes.springboot.security.jwt.service;
import io.jsonwebtoken.*;
import io.jsonwebtoken.security.Keys;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Service;
import java.security.Key;
import java.util.Date;
@Service
public class JwtService {
private final String SECRET = "mySuperSecretKey12345678901234567890"; // 256-bit key
public String generateToken(UserDetails userDetails) {
return Jwts.builder()
.setSubject(userDetails.getUsername())
.setIssuedAt(new Date(System.currentTimeMillis()))
.setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 60)) // 1 hour
.signWith(getSignKey(), SignatureAlgorithm.HS256)
.compact();
}
public boolean isTokenValid(String token, UserDetails userDetails) {
final String username = extractUsername(token);
return (username.equals(userDetails.getUsername()) && !isTokenExpired(token));
}
public String extractUsername(String token) {
return extractClaims(token).getSubject();
}
private boolean isTokenExpired(String token) {
return extractClaims(token).getExpiration().before(new Date());
}
private Claims extractClaims(String token) {
return Jwts.parserBuilder()
.setSigningKey(getSignKey())
.build()
.parseClaimsJws(token)
.getBody();
}
private Key getSignKey() {
return Keys.hmacShaKeyFor(SECRET.getBytes());
}
}
๐งฑ JWT Authentication Filter
JwtAuthenticationFilter.java
package com.kscodes.springboot.security.jwt.filter;
import com.kscodes.springboot.security.jwt.service.JwtService;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import java.io.IOException;
@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {
private final JwtService jwtService;
private final UserDetailsService userDetailsService;
public JwtAuthenticationFilter(JwtService jwtService, UserDetailsService userDetailsService) {
this.jwtService = jwtService;
this.userDetailsService = userDetailsService;
}
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain filterChain)
throws ServletException, IOException {
final String authHeader = request.getHeader("Authorization");
final String jwt;
final String username;
if (authHeader == null || !authHeader.startsWith("Bearer ")) {
filterChain.doFilter(request, response);
return;
}
jwt = authHeader.substring(7);
username = jwtService.extractUsername(jwt);
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
UserDetails userDetails = this.userDetailsService.loadUserByUsername(username);
if (jwtService.isTokenValid(jwt, userDetails)) {
UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(
userDetails, null, userDetails.getAuthorities());
SecurityContextHolder.getContext().setAuthentication(authToken);
}
}
filterChain.doFilter(request, response);
}
}
๐ Authentication Controller
AuthController.java
package com.kscodes.springboot.security.jwt.controller;
import com.kscodes.springboot.security.jwt.model.AuthRequest;
import com.kscodes.springboot.security.jwt.service.JwtService;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/api/auth")
public class AuthController {
private final JwtService jwtService;
private final AuthenticationManager authenticationManager;
private final UserDetailsService userDetailsService;
public AuthController(JwtService jwtService,
AuthenticationManager authenticationManager,
UserDetailsService userDetailsService) {
this.jwtService = jwtService;
this.authenticationManager = authenticationManager;
this.userDetailsService = userDetailsService;
}
@PostMapping("/login")
public String authenticate(@RequestBody AuthRequest authRequest) {
authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(authRequest.getUsername(), authRequest.getPassword())
);
UserDetails userDetails = userDetailsService.loadUserByUsername(authRequest.getUsername());
return jwtService.generateToken(userDetails);
}
}
๐ Secured API Endpoint Example
@RestController
@RequestMapping("/api/user")
public class UserController {
@GetMapping("/profile")
public String profile() {
return "This is a secured profile endpoint.";
}
}
๐งช Testing the Flow
1. Authenticate and get token
curl -X POST http://localhost:8080/api/auth/login \
-H "Content-Type: application/json" \
-d '{"username":"user", "password":"password"}'
๐ฅ Response:"eyJhbGciOiJIUzI1NiJ9..."
Access secured endpoint
curl http://localhost:8080/api/user/profile \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiJ9..."
โ
Response:This is a secured profile endpoint.
๐ Conclusion
JWT Authentication with Spring Security 6 in a Spring Boot 3 application offers a stateless and secure mechanism to authenticate and authorize API access. With updated components like SecurityFilterChain and modern JWT libraries, you can implement a clean and efficient security layer with minimal overhead.