0
0
SpringbootHow-ToBeginner · 4 min read

How to Use JWT Authentication in Spring Boot: Simple Guide

To use JWT authentication in Spring Boot, create a filter that intercepts requests to validate the JWT token, configure security to use this filter, and generate tokens upon user login. The token carries user identity and permissions securely, allowing stateless authentication.
📐

Syntax

This is the basic pattern to implement JWT authentication in Spring Boot:

  • Create a JwtTokenProvider to generate and validate tokens.
  • Implement a JwtAuthenticationFilter to check tokens on incoming requests.
  • Configure SecurityFilterChain to use the JWT filter and set authorization rules.
  • Create login endpoint to authenticate users and return JWT tokens.
java
public class JwtTokenProvider {
    private final String secretKey = "your-secret-key";
    private final long validityInMilliseconds = 3600000; // 1h

    public String createToken(String username) {
        Claims claims = Jwts.claims().setSubject(username);
        Date now = new Date();
        Date validity = new Date(now.getTime() + validityInMilliseconds);

        return Jwts.builder()
            .setClaims(claims)
            .setIssuedAt(now)
            .setExpiration(validity)
            .signWith(SignatureAlgorithm.HS256, secretKey)
            .compact();
    }

    public boolean validateToken(String token) {
        try {
            Jwts.parser().setSigningKey(secretKey).parseClaimsJws(token);
            return true;
        } catch (JwtException | IllegalArgumentException e) {
            return false;
        }
    }

    public String getUsername(String token) {
        return Jwts.parser().setSigningKey(secretKey).parseClaimsJws(token).getBody().getSubject();
    }
}
💻

Example

This example shows a simple Spring Boot setup with JWT authentication. It includes a token provider, a filter to check tokens, and a security configuration that applies the filter. The /login endpoint returns a JWT token after validating user credentials.

java
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.Authentication;
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.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.bind.annotation.*;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@SpringBootApplication
public class JwtAuthApplication {

    public static void main(String[] args) {
        SpringApplication.run(JwtAuthApplication.class, args);
    }

    @Bean
    public JwtTokenProvider jwtTokenProvider() {
        return new JwtTokenProvider();
    }

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http, JwtTokenProvider jwtTokenProvider) throws Exception {
        JwtAuthenticationFilter jwtFilter = new JwtAuthenticationFilter(jwtTokenProvider);

        http.csrf().disable()
            .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
            .and()
            .authorizeHttpRequests(auth -> auth
                .requestMatchers("/login").permitAll()
                .anyRequest().authenticated()
            )
            .addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter.class);

        return http.build();
    }

    @Bean
    public AuthenticationManager authenticationManager(AuthenticationConfiguration config) throws Exception {
        return config.getAuthenticationManager();
    }

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

    @Bean
    public UserDetailsService userDetailsService() {
        return username -> User.withUsername(username)
            .password(passwordEncoder().encode("password"))
            .roles("USER")
            .build();
    }
}

class JwtAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
    private final JwtTokenProvider jwtTokenProvider;

    public JwtAuthenticationFilter(JwtTokenProvider jwtTokenProvider) {
        this.jwtTokenProvider = jwtTokenProvider;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        String header = request.getHeader("Authorization");
        if (header != null && header.startsWith("Bearer ")) {
            String token = header.substring(7);
            if (jwtTokenProvider.validateToken(token)) {
                String username = jwtTokenProvider.getUsername(token);
                Authentication auth = new UsernamePasswordAuthenticationToken(username, null, java.util.Collections.emptyList());
                // Set authentication in context
                org.springframework.security.core.context.SecurityContextHolder.getContext().setAuthentication(auth);
            }
        }
        chain.doFilter(request, response);
    }
}

@RestController
class AuthController {
    private final AuthenticationManager authenticationManager;
    private final JwtTokenProvider jwtTokenProvider;

    public AuthController(AuthenticationManager authenticationManager, JwtTokenProvider jwtTokenProvider) {
        this.authenticationManager = authenticationManager;
        this.jwtTokenProvider = jwtTokenProvider;
    }

    record LoginRequest(String username, String password) {}

    @PostMapping("/login")
    public String login(@RequestBody LoginRequest request) {
        Authentication auth = authenticationManager.authenticate(
            new UsernamePasswordAuthenticationToken(request.username(), request.password())
        );
        return jwtTokenProvider.createToken(auth.getName());
    }
}
Output
POST /login with JSON {"username":"user","password":"password"} returns a JWT token string.
⚠️

Common Pitfalls

Common mistakes include:

  • Not setting the Authorization header with Bearer <token> format.
  • Using a weak or hardcoded secret key for signing tokens.
  • Not configuring the security filter chain to be stateless, causing session conflicts.
  • Failing to handle token expiration properly, leading to unauthorized errors.

Always validate tokens and handle exceptions gracefully.

text
/* Wrong: Missing Bearer prefix in header */
// Request header: Authorization: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

/* Right: Include Bearer prefix */
// Request header: Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
📊

Quick Reference

  • JwtTokenProvider: Create, validate, and parse JWT tokens.
  • JwtAuthenticationFilter: Intercepts requests to check JWT tokens.
  • SecurityFilterChain: Configure stateless security and add JWT filter.
  • Login endpoint: Authenticates user and returns JWT token.

Key Takeaways

Use a JwtTokenProvider to generate and validate JWT tokens securely.
Add a JwtAuthenticationFilter in the security chain to check tokens on each request.
Configure Spring Security to be stateless to avoid session conflicts with JWT.
Always prefix tokens with 'Bearer ' in the Authorization header.
Handle token expiration and invalid tokens gracefully to improve security.