spring-boot-security-jwt

Spring Boot JWT Security

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "spring-boot-security-jwt" with this command: npx skills add giuseppe-trisciuoglio/developer-kit/giuseppe-trisciuoglio-developer-kit-spring-boot-security-jwt

Spring Boot JWT Security

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.

Overview

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:

  • Access and refresh token generation with configurable expiration

  • Bearer token and HttpOnly cookie authentication strategies

  • Integration with Spring Data JPA and OAuth2 providers

  • RBAC with role/permission-based @PreAuthorize rules

  • Token revocation and blacklisting for logout/rotation

When to Use

Activate when user requests involve:

  • "Implement JWT authentication", "secure REST API with tokens"

  • "Spring Security 6.x configuration", "SecurityFilterChain setup"

  • "Role-based access control", "RBAC", @PreAuthorize

  • "Refresh token", "token rotation", "token revocation"

  • "OAuth2 integration", "social login", "Google/GitHub auth"

  • "Stateless authentication", "SPA backend security"

  • "JWT filter", "OncePerRequestFilter", "Bearer token"

  • "Cookie-based JWT", "HttpOnly cookie"

  • "Permission-based access control", "custom PermissionEvaluator"

Quick Reference

Dependencies (JJWT 0.12.6)

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.

Key Configuration Properties

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

Authorization Annotations

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

Instructions

Step 1 — Add Dependencies

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.

Step 2 — Configure application.yml

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.

Step 3 — Implement JwtService

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.

Step 4 — Create JwtAuthenticationFilter

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.

Step 5 — Configure SecurityFilterChain

@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.

Step 6 — Create Authentication Endpoints

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 .

Step 7 — Implement Refresh Token Strategy

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.

Step 8 — Add Authorization Rules

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.

Step 9 — Write Security Tests

@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.

Best Practices

Token Security

  • Use minimum 256-bit secret keys — load from environment variables, never hardcode

  • Set short access token lifetimes (15 min); use refresh tokens for longer sessions

  • Implement token rotation: revoke old refresh token when issuing a new one

  • Use jti (JWT ID) claim for blacklisting on logout

Cookie vs Bearer Header

  • Prefer HttpOnly cookies for browser clients (XSS-safe)

  • Use Authorization: Bearer header for mobile/API clients

  • Set Secure , SameSite=Lax or Strict on cookies in production

Spring Security 6.x

  • Use SecurityFilterChain bean — never extend WebSecurityConfigurerAdapter

  • Disable CSRF only for stateless APIs; keep it enabled for session-based flows

  • Use @EnableMethodSecurity instead of deprecated @EnableGlobalMethodSecurity

  • Validate iss and aud claims; reject tokens from untrusted issuers

Performance

  • Cache UserDetails with @Cacheable to avoid DB lookup on every request

  • Cache signing key derivation (avoid re-computing HMAC key per request)

  • Use Redis for refresh token storage at scale

What NOT to Do

  • Do not store sensitive data (passwords, PII) in JWT claims — claims are only signed, not encrypted

  • Do not issue tokens with infinite lifetime

  • Do not accept tokens without validating signature and expiration

  • Do not share signing keys across environments

Examples

Basic Authentication Flow

@RestController @RequestMapping("/api/auth") @RequiredArgsConstructor public class AuthController {

private final AuthService authService;

@PostMapping("/authenticate")
public ResponseEntity&#x3C;AuthResponse> authenticate(
        @RequestBody LoginRequest request) {
    return ResponseEntity.ok(authService.authenticate(request));
}

@PostMapping("/refresh")
public ResponseEntity&#x3C;AuthResponse> refresh(@RequestBody RefreshRequest request) {
    return ResponseEntity.ok(authService.refreshToken(request.refreshToken()));
}

@PostMapping("/logout")
public ResponseEntity&#x3C;Void> logout() {
    authService.logout();
    return ResponseEntity.ok().build();
}

}

JWT Authorization on Controller Method

@RestController @RequestMapping("/api/admin") @PreAuthorize("hasRole('ADMIN')") public class AdminController {

@GetMapping("/users")
public ResponseEntity&#x3C;List&#x3C;UserResponse>> getAllUsers() {
    return ResponseEntity.ok(adminService.getAllUsers());
}

}

See references/examples.md for complete entity models and service implementations.

References

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

Constraints and Warnings

Security Constraints

  • JWT tokens are signed but not encrypted — do not include sensitive data in claims

  • Always validate exp , iss , and aud claims before trusting the token

  • Signing keys must be at least 256 bits; never use weak keys in production

  • Load secrets from environment variables or secure vaults, never from config files

  • SameSite cookie attribute is essential for CSRF protection in cookie-based flows

Spring Security 6.x Constraints

  • WebSecurityConfigurerAdapter is removed — use SecurityFilterChain beans only

  • @EnableGlobalMethodSecurity is deprecated — use @EnableMethodSecurity

  • Lambda DSL is required for HttpSecurity configuration (no method chaining)

  • WebSecurityConfigurerAdapter.order() replaced by @Order on @Configuration classes

Token Constraints

  • Access tokens should expire in 5-15 minutes for security

  • Refresh tokens should be stored server-side (DB or Redis), never in localStorage

  • Implement token blacklisting for immediate revocation on logout

  • jti claim is required for token blacklisting to work correctly

Related Skills

  • spring-boot-dependency-injection — Constructor injection patterns used throughout

  • spring-boot-rest-api-standards — REST API security patterns and error handling

  • unit-test-security-authorization — Testing Spring Security configurations

  • spring-data-jpa — User entity and repository patterns

  • spring-boot-actuator — Security monitoring and health endpoints

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Security

unit-test-security-authorization

No summary provided by upstream source.

Repository SourceNeeds Review
Security

typescript-security-review

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

shadcn-ui

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

tailwind-css-patterns

No summary provided by upstream source.

Repository SourceNeeds Review