Implements JWT authentication and authorization patterns for Spring Boot 3.5.x using Spring Security 6.x and JJWT: token generation, Bearer/cookie auth, refresh tokens, OAuth2 integration, RBAC permissions. Use for securing REST APIs.
From developer-kit-javanpx claudepluginhub giuseppe-trisciuoglio/developer-kit --plugin developer-kit-javaThis skill is limited to using the following tools:
assets/generate-jwt-keys.shreferences/authorization-patterns.mdreferences/configuration.mdreferences/examples.mdreferences/jwt-complete-configuration.mdreferences/jwt-configuration.mdreferences/jwt-quick-reference.mdreferences/jwt-testing-guide.mdreferences/microservices-security.mdreferences/migration-spring-security-6x.mdreferences/oauth2-integration.mdreferences/performance-optimization.mdreferences/security-hardening.mdreferences/structure.mdreferences/testing-jwt-security.mdreferences/testing.mdreferences/token-management.mdreferences/troubleshooting.mdscripts/test-jwt-setup.shSearches, retrieves, and installs Agent Skills from prompts.chat registry using MCP tools like search_skills and get_skill. Activates for finding skills, browsing catalogs, or extending Claude.
Searches prompts.chat for AI prompt templates by keyword or category, retrieves by ID with variable handling, and improves prompts via AI. Use for discovering or enhancing prompts.
Enables AI agents to execute x402 payments with per-task budgets, spending controls, and non-custodial wallets via MCP tools. Use when agents pay for APIs, services, or other agents.
JWT authentication and authorization patterns for Spring Boot 3.5.x using Spring Security 6.x and JJWT. Covers token generation, validation, refresh strategies, RBAC/ABAC, and OAuth2 integration.
This skill provides implementation patterns for stateless JWT authentication in Spring Boot applications. It covers the complete authentication flow including token generation with JJWT 0.12.6, Bearer/cookie-based authentication, refresh token rotation, and method-level authorization with @PreAuthorize expressions.
Key capabilities:
@PreAuthorize rulesActivate when user requests involve:
`@PreAuthorize`| Artifact | Scope |
|---|---|
spring-boot-starter-security | compile |
spring-boot-starter-oauth2-resource-server | compile |
io.jsonwebtoken:jjwt-api:0.12.6 | compile |
io.jsonwebtoken:jjwt-impl:0.12.6 | runtime |
io.jsonwebtoken:jjwt-jackson:0.12.6 | runtime |
spring-security-test | test |
See references/jwt-quick-reference.md for Maven and Gradle snippets.
| Property | Example Value | Notes |
|---|---|---|
jwt.secret | ${JWT_SECRET} | Min 256 bits, never hardcode |
jwt.access-token-expiration | 900000 | 15 min in milliseconds |
jwt.refresh-token-expiration | 604800000 | 7 days in milliseconds |
jwt.issuer | my-app | Validated on every token |
jwt.cookie-name | jwt-token | For cookie-based auth |
jwt.cookie-http-only | true | Always true in production |
jwt.cookie-secure | true | Always true with HTTPS |
| Annotation | Example |
|---|---|
@PreAuthorize("hasRole('ADMIN')") | Role check |
@PreAuthorize("hasAuthority('USER_READ')") | Permission check |
@PreAuthorize("hasPermission(#id, 'Doc', 'READ')") | Domain object check |
@PreAuthorize("@myService.canAccess(#id)") | Spring bean check |
Include spring-boot-starter-security, spring-boot-starter-oauth2-resource-server, and the three JJWT artifacts in your build file. See references/jwt-quick-reference.md for exact Maven/Gradle snippets.
jwt:
secret: ${JWT_SECRET:change-me-min-32-chars-in-production}
access-token-expiration: 900000
refresh-token-expiration: 604800000
issuer: my-app
cookie-name: jwt-token
cookie-http-only: true
cookie-secure: false # true in production
See references/jwt-complete-configuration.md for the full properties reference.
Core operations: generate access token, generate refresh token, extract username, validate token.
@Service
public class JwtService {
public String generateAccessToken(UserDetails userDetails) {
return Jwts.builder()
.subject(userDetails.getUsername())
.issuer(issuer)
.issuedAt(new Date())
.expiration(new Date(System.currentTimeMillis() + accessTokenExpiration))
.claim("authorities", getAuthorities(userDetails))
.signWith(getSigningKey())
.compact();
}
public boolean isTokenValid(String token, UserDetails userDetails) {
try {
String username = extractUsername(token);
return username.equals(userDetails.getUsername()) && !isTokenExpired(token);
} catch (JwtException e) {
return false;
}
}
}
See references/jwt-complete-configuration.md for the complete JwtService including key management and claim extraction.
Extend OncePerRequestFilter to extract a JWT from the Authorization: Bearer header (or HttpOnly cookie), validate it, and set the SecurityContext.
@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response, FilterChain chain)
throws ServletException, IOException {
String authHeader = request.getHeader("Authorization");
if (authHeader == null || !authHeader.startsWith("Bearer ")) {
chain.doFilter(request, response);
return;
}
String jwt = authHeader.substring(7);
String username = jwtService.extractUsername(jwt);
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
if (jwtService.isTokenValid(jwt, userDetails)) {
UsernamePasswordAuthenticationToken authToken =
new UsernamePasswordAuthenticationToken(
userDetails, null, userDetails.getAuthorities());
authToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authToken);
}
}
chain.doFilter(request, response);
}
}
See references/configuration.md for the cookie-based variant.
@Configuration
@EnableWebSecurity
@EnableMethodSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
return http
.csrf(AbstractHttpConfigurer::disable)
.sessionManagement(s -> s.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/auth/**", "/swagger-ui/**").permitAll()
.anyRequest().authenticated()
)
.authenticationProvider(authenticationProvider)
.addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class)
.build();
}
}
See references/jwt-complete-configuration.md for CORS, logout handler, and OAuth2 login integration.
Expose /register, /authenticate, /refresh, and /logout via @RestController. Return accessToken + refreshToken in the response body (and optionally set an HttpOnly cookie).
See references/examples.md for the complete AuthenticationController and AuthenticationService.
Store refresh tokens in the database with user_id, expiry_date, revoked, and expired columns. On /refresh, verify the stored token, revoke it, and issue a new pair (token rotation).
See references/token-management.md for RefreshToken entity, rotation logic, and Redis-based blacklisting.
Use @EnableMethodSecurity and @PreAuthorize annotations for fine-grained control:
@PreAuthorize("hasRole('ADMIN')")
public Page<UserResponse> getAllUsers(Pageable pageable) { ... }
@PreAuthorize("hasPermission(#documentId, 'Document', 'READ')")
public Document getDocument(Long documentId) { ... }
See references/authorization-patterns.md for RBAC entity model, PermissionEvaluator, and ABAC patterns.
@SpringBootTest
@AutoConfigureMockMvc
class AuthControllerTest {
@Test
void shouldDenyAccessWithoutToken() throws Exception {
mockMvc.perform(get("/api/orders"))
.andExpect(status().isUnauthorized());
}
@Test
@WithMockUser(roles = "ADMIN")
void shouldAllowAdminAccess() throws Exception {
mockMvc.perform(get("/api/admin/users"))
.andExpect(status().isOk());
}
}
See references/testing.md and references/jwt-testing-guide.md for full test suites, Testcontainers setup, and a security test checklist.
jti (JWT ID) claim for blacklisting on logoutAuthorization: Bearer header for mobile/API clientsSecure, SameSite=Lax or Strict on cookies in productionSecurityFilterChain bean — never extend WebSecurityConfigurerAdapter@EnableMethodSecurity instead of deprecated @EnableGlobalMethodSecurityiss and aud claims; reject tokens from untrusted issuersUserDetails with @Cacheable to avoid DB lookup on every request@RestController
@RequestMapping("/api/auth")
@RequiredArgsConstructor
public class AuthController {
private final AuthService authService;
@PostMapping("/authenticate")
public ResponseEntity<AuthResponse> authenticate(
@RequestBody LoginRequest request) {
return ResponseEntity.ok(authService.authenticate(request));
}
@PostMapping("/refresh")
public ResponseEntity<AuthResponse> refresh(@RequestBody RefreshRequest request) {
return ResponseEntity.ok(authService.refreshToken(request.refreshToken()));
}
@PostMapping("/logout")
public ResponseEntity<Void> logout() {
authService.logout();
return ResponseEntity.ok().build();
}
}
@RestController
@RequestMapping("/api/admin")
@PreAuthorize("hasRole('ADMIN')")
public class AdminController {
@GetMapping("/users")
public ResponseEntity<List<UserResponse>> getAllUsers() {
return ResponseEntity.ok(adminService.getAllUsers());
}
}
See references/examples.md for complete entity models and service implementations.
| File | Content |
|---|---|
| references/jwt-quick-reference.md | Dependencies, minimal service, common patterns |
| references/jwt-complete-configuration.md | Full config: properties, SecurityFilterChain, JwtService, OAuth2 RS |
| references/configuration.md | JWT config beans, CORS, CSRF, error handling, session options |
| references/examples.md | Complete application setup: controllers, services, entities |
| references/authorization-patterns.md | RBAC/ABAC entity model, PermissionEvaluator, SpEL expressions |
| references/token-management.md | Refresh token entity, rotation, blacklisting with Redis |
| references/testing.md | Unit and MockMvc tests, test utilities |
| references/jwt-testing-guide.md | Testcontainers, load testing, security test checklist |
| references/security-hardening.md | Security headers, HSTS, rate limiting, audit logging |
| references/performance-optimization.md | Caffeine cache config, async validation, connection pooling |
| references/oauth2-integration.md | Google/GitHub OAuth2 login, OAuth2UserService |
| references/microservices-security.md | Inter-service JWT propagation, resource server config |
| references/migration-spring-security-6x.md | Migration from Spring Security 5.x |
| references/troubleshooting.md | Common errors, debugging tips |
exp, iss, and aud claims before trusting the tokenWebSecurityConfigurerAdapter is removed — use SecurityFilterChain beans only@EnableGlobalMethodSecurity is deprecated — use @EnableMethodSecurityHttpSecurity configuration (no method chaining)WebSecurityConfigurerAdapter.order() replaced by @Order on @Configuration classesjti claim is required for token blacklisting to work correctlyspring-boot-dependency-injection — Constructor injection patterns used throughoutspring-boot-rest-api-standards — REST API security patterns and error handlingunit-test-security-authorization — Testing Spring Security configurationsspring-data-jpa — User entity and repository patternsspring-boot-actuator — Security monitoring and health endpoints