Table of Contents
- Introduction to JWT
- How JWT Works (Stateless Auth)
- Benefits of JWT in Spring Applications
- Generating JWT Tokens
- Validating JWT Tokens
- Creating a Custom Filter
- Configuring Spring Security for JWT
- Testing the Full Flow
- Best Practices
- Summary
1. Introduction to JWT
JSON Web Tokens (JWT) are a compact, URL-safe means of representing claims to be transferred between two parties. In the context of Spring Security, JWTs are used to authorize users in a stateless manner—no server-side session storage is required.
A JWT typically contains three parts:
- Header: Type and signing algorithm.
- Payload: User information and claims.
- Signature: Verifies the token wasn’t tampered with.
2. How JWT Works (Stateless Auth)
In JWT-based stateless authentication:
- The user logs in with credentials.
- Server authenticates and returns a signed JWT token.
- The client stores the JWT (usually in localStorage or cookies).
- For each request, the client sends the token in the Authorization header.
- The server verifies the token and processes the request.
3. Benefits of JWT in Spring Applications
- Stateless: No session storage on server.
- Scalable: Ideal for distributed systems.
- Self-contained: Carries user data and metadata.
- Cross-platform: Can be used across languages and services.
4. Generating JWT Tokens
Use a utility class to generate tokens:
javaCopyEditpublic class JwtUtil {
private final String SECRET_KEY = "your-secret";
public String generateToken(UserDetails userDetails) {
return Jwts.builder()
.setSubject(userDetails.getUsername())
.claim("roles", userDetails.getAuthorities())
.setIssuedAt(new Date(System.currentTimeMillis()))
.setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 10)) // 10 hrs
.signWith(SignatureAlgorithm.HS256, SECRET_KEY)
.compact();
}
}
5. Validating JWT Tokens
javaCopyEditpublic boolean validateToken(String token, UserDetails userDetails) {
final String username = extractUsername(token);
return (username.equals(userDetails.getUsername()) && !isTokenExpired(token));
}
You’ll also need methods like extractUsername()
, extractExpiration()
etc., using Jwts.parser()
.
6. Creating a Custom JWT Filter
This filter intercepts requests, extracts the JWT, and sets the security context.
javaCopyEditpublic class JwtRequestFilter extends OncePerRequestFilter {
@Autowired
private JwtUtil jwtUtil;
@Autowired
private UserDetailsService userDetailsService;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
throws ServletException, IOException {
final String authHeader = request.getHeader("Authorization");
String username = null;
String jwt = null;
if (authHeader != null && authHeader.startsWith("Bearer ")) {
jwt = authHeader.substring(7);
username = jwtUtil.extractUsername(jwt);
}
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
UserDetails userDetails = this.userDetailsService.loadUserByUsername(username);
if (jwtUtil.validateToken(jwt, userDetails)) {
UsernamePasswordAuthenticationToken token =
new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
token.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(token);
}
}
chain.doFilter(request, response);
}
}
7. Configuring Spring Security for JWT
Update your security configuration:
javaCopyEdit@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Autowired
private JwtRequestFilter jwtRequestFilter;
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeHttpRequests()
.requestMatchers("/authenticate").permitAll()
.anyRequest().authenticated()
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
return http.build();
}
}
8. Testing the Full Flow
- Authenticate:
- POST to
/authenticate
with username and password. - Receive JWT token.
- POST to
- Access Protected Resource:
- Set header:
Authorization: Bearer <token>
- GET
/api/protected
– success if token is valid.
- Set header:
9. Best Practices
- Always sign tokens with a strong secret or RSA keys.
- Use HTTPS to secure tokens in transit.
- Set short expiration times and refresh tokens.
- Avoid storing JWTs in localStorage on browsers prone to XSS.
- Use claim fields wisely—don’t overstuff JWTs.
10. Summary
JWT-based authentication provides a scalable, stateless solution for securing your Spring Boot APIs. It avoids session storage, making it ideal for RESTful microservices.
Key Concepts Covered:
- What JWT is and how it works
- How to generate, sign, and validate tokens
- Creating a custom JWT filter
- Securing endpoints using JWT