From developer-kit-java
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.
How this skill is triggered — by the user, by Claude, or both
Slash command
/developer-kit-java:spring-boot-security-jwtThis skill is limited to the following tools:
The summary Claude sees in its skill listing — used to decide when to auto-load this skill
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.
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.shJWT 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 endpointsnpx claudepluginhub giuseppe-trisciuoglio/developer-kit --plugin developer-kit-javaReviews existing Spring Security configs or implements JWT auth, OAuth2, method-level security, CORS, and CSRF in Spring Boot projects. Audits for OWASP issues like exposed actuators and weak hashing.
Generates a Spring Security configuration class with authentication, authorization, and HTTP protection. Supports OAuth2/OIDC login and JWT resource server setup.
Secures Spring Boot API endpoints with JWT Bearer token validation, scope-based authorization, and DPoP proof-of-possession using Auth0 SDK.