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
JwtTokenProviderto generate and validate tokens. - Implement a
JwtAuthenticationFilterto check tokens on incoming requests. - Configure
SecurityFilterChainto 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
Authorizationheader withBearer <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.