JWT is best when you want stateless authentication, especially across distributed systems like microservices. Session-based authentication keeps state on the server, which can be harder to scale.
JWT tokens carry their own expiration and the client must request a new token after expiry. Sessions expire on the server side and require server cleanup.
If the server's clock is ahead, it may consider the token expired even if the client just received it. This causes valid tokens to be rejected.
Session data is stored in server memory by default. Without persistence, restarting the server clears all sessions, forcing users to log in again.
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
return http
.csrf(csrf -> csrf.disable())
.authorizeHttpRequests(auth -> auth
.requestMatchers("/public/**").permitAll()
.anyRequest().authenticated()
)
.addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter.class)
.build();
}The JWT filter must run before UsernamePasswordAuthenticationFilter to extract and validate the token before Spring Security processes authentication.