Building a Secure JWT Authentication Filter in Spring Boot 3
Introduction to Secure JWT Authentication in Spring Boot 3
With the rise of microservices and stateless architectures, JSON Web Tokens (JWT) have become a de facto standard for authentication and authorization. In this comprehensive guide, we will walk through the process of building a secure JWT authentication filter in Spring Boot 3, leveraging the power of Spring Security 6.
Understanding JWT and Spring Security 6
Before diving into the implementation, let's quickly review the basics of JWT and Spring Security 6. JWT is a compact, URL-safe means of representing claims to be transferred between two parties. Spring Security 6, on the other hand, provides a robust security framework for building secure applications.
Implementing the JWT Utility Class
To start, we need a utility class that will handle the creation and verification of JWT tokens. Here's an example implementation in Java:
public class JwtUtil {
private static final String SECRET_KEY = 'your-secret-key';
private static final int TOKEN_VALIDITY = 24 * 60 * 60 * 1000; // 1 day
public String generateToken(String username) {
String token = Jwts.builder()
.setSubject(username)
.setIssuedAt(new Date())
.setExpiration(new Date(System.currentTimeMillis() + TOKEN_VALIDITY))
.signWith(SignatureAlgorithm.HS512, SECRET_KEY)
.compact();
return token;
}
public boolean validateToken(String token, String username) {
try {
Jws claims = Jwts.parser()
.setSigningKey(SECRET_KEY)
.parseClaimsJws(token);
return claims.getBody().getSubject().equals(username);
} catch (SignatureException | MalformedJwtException | ExpiredJwtException | UnsupportedJwtException | IllegalArgumentException e) {
return false;
}
}
}
Creating a Custom OncePerRequestFilter
Next, we need to create a custom filter that will intercept incoming requests and verify the JWT token. We'll extend the OncePerRequestFilter class:
public class JwtAuthenticationFilter extends OncePerRequestFilter {
@Autowired
private JwtUtil jwtUtil;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
String token = request.getHeader('Authorization');
if (token != null && token.startsWith('Bearer ')) {
token = token.substring(7);
String username = jwtUtil.getUsernameFromToken(token);
if (jwtUtil.validateToken(token, username)) {
// token is valid, proceed with the request
filterChain.doFilter(request, response);
} else {
// token is invalid, return an error response
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, 'Invalid token');
}
} else {
// no token provided, return an error response
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, 'No token provided');
}
}
}
Configuring the SecurityFilterChain
Finally, we need to configure the SecurityFilterChain to include our custom filter. Here's an example configuration using the lambda syntax:
@Configuration
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.csrf(csrf -> csrf.disable())
.authorizeRequests(auth -> auth
.antMatchers('/login').permitAll()
.anyRequest().authenticated()
)
.oauth2ResourceServer(oauth2 -> oauth2
.jwt(jwt -> jwt
.jwtAuthenticationConverter(jwtAuthenticationConverter())
)
);
return http.build();
}
@Bean
public JwtAuthenticationConverter jwtAuthenticationConverter() {
JwtAuthenticationConverter converter = new JwtAuthenticationConverter();
converter.setJwtValidator(new JwtUtil());
return converter;
}
}
Conclusion and Next Steps
In this guide, we've walked through the process of building a secure JWT authentication filter in Spring Boot 3 using Spring Security 6. By following these steps, you can add robust authentication and authorization to your application. Remember to replace the secret key and token validity values with your own secure values.
As you continue to build and secure your application, keep in mind the importance of staying up-to-date with the latest security best practices and Spring Boot releases.