Clean • Professional
JWT Authentication is a stateless, token-based security mechanism widely used to secure REST APIs and microservices in Spring Boot. It eliminates server-side sessions and is ideal for scalable, cloud-native applications.
JWT (JSON Web Token) is a compact, URL-safe token used to securely transmit information between a client and server.
A JWT has three parts:

JWTs are signed, not encrypted (unless using JWE).
Example: Generating a JWT Token
Stringtoken= Jwts.builder()
.setSubject(user.getUsername())
.claim("roles", user.getAuthorities())
.setIssuedAt(newDate())
.setExpiration(newDate(System.currentTimeMillis() +1000 *60 *10))// 10 min
.signWith(SignatureAlgorithm.HS256,"mysecret123")
.compact();
System.out.println("Generated Token: " + token);
Practical Exercise: Try generating a token for a dummy user and decoding it using https://jwt.io.
Authorization: Bearer <JWT>
6. Server validates token → allows or denies access
Example: Login API
@PostMapping("/auth/login")
public ResponseEntity<?> login(@RequestBody AuthRequest request) {
authenticationManager.authenticate(
newUsernamePasswordAuthenticationToken(request.getUsername(), request.getPassword())
);
UserDetailsuser= userDetailsService.loadUserByUsername(request.getUsername());
Stringtoken= jwtUtil.generateToken(user);
return ResponseEntity.ok(Map.of("accessToken", token));
}
Client → Login API → JWTGenerated Client → AuthorizationHeader → JWTFilter JWTFilter → Validate Token → Security Context Controller → Protected Resource
| Aspect | Access Token | Refresh Token |
|---|---|---|
| Purpose | Access protected APIs | Generate a new access token |
| When Used | Sent with every API request | Used only when access token expires |
| Lifetime | Short-lived (5–15 minutes) | Long-lived (days or weeks) |
| How It Is Sent | Authorization: Bearer <token> | Sent to refresh endpoint (e.g. /auth/refresh) |
| Client Storage | Memory / HTTP header | Secure storage (HttpOnly cookie preferred) |
| Server Storage | Not stored (stateless) | Stored in DB / Redis |
| Security Risk if Leaked | Lower (expires quickly) | Higher (can issue new access tokens) |
| Revocation | Auto-expire | Can be revoked / blacklisted |
| Token Rotation | Not required | Recommended |
| Contains User Data | Yes (user, roles, expiry) | Minimal or reference only |
| Best Use Case | API authorization | Maintain login without re-login |
| Spring Security Usage | Validated in JWT Filter | Validated in Refresh API |
Implement /auth/refresh endpoint with token rotation
@PostMapping("/auth/refresh")
public ResponseEntity<?> refresh(@RequestBody Map<String, String> request) {
StringrefreshToken= request.get("refreshToken");
// Validate refresh token and rotate
StringnewAccessToken= jwtUtil.generateToken(userDetailsService.loadUserByUsername("admin"));
StringnewRefreshToken= UUID.randomUUID().toString();// simple rotation
return ResponseEntity.ok(Map.of("accessToken", newAccessToken,"refreshToken", newRefreshToken));
}
Refresh Token Rotation means issuing a new refresh token every time the old one is used.
Why Rotation Is Needed
Implement refresh token rotation by storing refresh tokens in Redis or DB and invalidating used tokens.
Refresh Token Rotation Flow
📌 If an old refresh token is reused → request is rejected.
JWTs cannot be revoked naturally. Token blacklisting solves this limitation.
When Blacklisting Is Required
How Blacklisting Works

Example: Check Blacklist in Filter
if(redisTemplate.hasKey(token)) {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED,"Token is blacklisted");
return;
}
JWT-based security in Spring Boot is built around a few core components. Each plays a specific role in authenticating users and securing API requests.
UserDetailsService & PasswordEncoderConfigure AuthenticationManager in SecurityConfig:
@Bean
public AuthenticationManagerauthManager(HttpSecurity http, BCryptPasswordEncoder encoder, CustomUserDetailsService userDetailsService)throws Exception {
return http.getSharedObject(AuthenticationManagerBuilder.class)
.userDetailsService(userDetailsService)
.passwordEncoder(encoder)
.and()
.build();
}
Add a method to extract roles from JWT for role-based access:
public List<String>extractRoles(String token) {
return ((List<?>) Jwts.parser().setSigningKey(SECRET_KEY)
.parseClaimsJws(token).getBody().get("roles")).stream()
.map(Object::toString).collect(Collectors.toList());
}
Test JWT filter by accessing /todos with and without a token.
STATELESS)Protect APIs selectively:
http.authorizeHttpRequests(auth -> auth
.requestMatchers("/auth/**").permitAll()
.requestMatchers("/admin/**").hasRole("ADMIN")
.anyRequest().authenticated()
);
| Feature | JWT Authentication | Session-Based Authentication |
|---|---|---|
| State | Stateless | Stateful |
| Scalability | High (easy horizontal scaling) | Limited (session sharing needed) |
| Server Storage | None | Session store (memory / DB) |
| Client Request | JWT sent in Authorization header | Session ID sent via cookie |
| Best Use Case | REST APIs, Microservices, Mobile apps | Traditional web applications |
| Performance | High (no session lookup) | Medium (session validation required) |
Use JWT (JSON Web Token) when your application needs stateless, scalable security.
Best Use Cases
Avoid JWT When
JWT Authentication is a modern, industry-standard approach to securing APIs. Mastering JWT in Spring Security helps you build: