Link copied to clipboard!
BlogForge AI

Building a Secure JWT Authentication Filter in Spring Boot 3

Building a Secure JWT Authentication Filter in Spring Boot 3

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.

💡 Key Takeaway: Always use a secure secret key and keep it confidential to prevent token tampering.

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.

Written by Chagalakonda Sandeep Krishna

Senior Java, Spring Boot & AI Engineer. Architecting modern enterprise backend systems.