spring-security

Spring Security - Quick Reference

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-security" with this command: npx skills add claude-dev-suite/claude-dev-suite/claude-dev-suite-claude-dev-suite-spring-security

Spring Security - Quick Reference

When to Use This Skill

  • Configure JWT authentication

  • Role-based access control

  • Method-level security

Deep Knowledge: Use mcp__documentation__fetch_docs with technology: spring-security for comprehensive documentation.

Essential Patterns

Security Config

@Configuration @EnableWebSecurity @EnableMethodSecurity @RequiredArgsConstructor public class SecurityConfig {

private final JwtAuthenticationFilter jwtAuthFilter;

@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    return http
        .csrf(AbstractHttpConfigurer::disable)
        .cors(Customizer.withDefaults())
        .sessionManagement(s -> s.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
        .authorizeHttpRequests(auth -> auth
            .requestMatchers("/api/v1/auth/**").permitAll()
            .requestMatchers("/swagger-ui/**", "/v3/api-docs/**").permitAll()
            .requestMatchers("/api/v1/admin/**").hasRole("ADMIN")
            .anyRequest().authenticated())
        .addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class)
        .build();
}

@Bean
public PasswordEncoder passwordEncoder() {
    return new BCryptPasswordEncoder();
}

}

JWT Filter

@Component @RequiredArgsConstructor public class JwtAuthenticationFilter extends OncePerRequestFilter {

private final JwtService jwtService;
private final UserDetailsService userDetailsService;

@Override
protected void doFilterInternal(HttpServletRequest request,
        HttpServletResponse response, FilterChain chain) throws Exception {

    String authHeader = request.getHeader("Authorization");
    if (authHeader == null || !authHeader.startsWith("Bearer ")) {
        chain.doFilter(request, response);
        return;
    }

    String jwt = authHeader.substring(7);
    String email = jwtService.extractUsername(jwt);

    if (email != null && SecurityContextHolder.getContext().getAuthentication() == null) {
        UserDetails user = userDetailsService.loadUserByUsername(email);
        if (jwtService.isTokenValid(jwt, user)) {
            var auth = new UsernamePasswordAuthenticationToken(user, null, user.getAuthorities());
            SecurityContextHolder.getContext().setAuthentication(auth);
        }
    }
    chain.doFilter(request, response);
}

}

Method Security

@PreAuthorize("hasRole('ADMIN')") @DeleteMapping("/{id}") public void delete(@PathVariable Long id) { ... }

@PreAuthorize("#id == authentication.principal.id or hasRole('ADMIN')") @GetMapping("/{id}/profile") public UserProfile getProfile(@PathVariable Long id) { ... }

UserDetails

public class UserPrincipal implements UserDetails { @Override public Collection<? extends GrantedAuthority> getAuthorities() { return List.of(new SimpleGrantedAuthority("ROLE_" + role.name())); } }

Common Annotations

Annotation Usage

@PreAuthorize

Check before method execution

hasRole('X')

Requires role

hasAnyRole

Any of the roles

Anti-Patterns to Avoid

  • Do not disable CSRF without stateless

  • Do not forget CORS for frontend

  • Do not hardcode JWT secret

Production Readiness

JWT Service

@Service @RequiredArgsConstructor public class JwtService {

@Value("${security.jwt.secret-key}")
private String secretKey;

@Value("${security.jwt.expiration}")
private long jwtExpiration;

@Value("${security.jwt.refresh-expiration}")
private long refreshExpiration;

public String generateToken(UserDetails userDetails) {
    return buildToken(userDetails, jwtExpiration);
}

public String generateRefreshToken(UserDetails userDetails) {
    return buildToken(userDetails, refreshExpiration);
}

private String buildToken(UserDetails userDetails, long expiration) {
    return Jwts.builder()
        .setSubject(userDetails.getUsername())
        .claim("roles", userDetails.getAuthorities().stream()
            .map(GrantedAuthority::getAuthority)
            .toList())
        .setIssuedAt(new Date())
        .setExpiration(new Date(System.currentTimeMillis() + expiration))
        .signWith(getSigningKey(), SignatureAlgorithm.HS256)
        .compact();
}

public boolean isTokenValid(String token, UserDetails userDetails) {
    try {
        final String username = extractUsername(token);
        return username.equals(userDetails.getUsername()) &#x26;&#x26; !isTokenExpired(token);
    } catch (ExpiredJwtException | MalformedJwtException e) {
        return false;
    }
}

private SecretKey getSigningKey() {
    byte[] keyBytes = Decoders.BASE64.decode(secretKey);
    return Keys.hmacShaKeyFor(keyBytes);
}

}

CORS Configuration

@Configuration public class CorsConfig {

@Bean
public CorsFilter corsFilter() {
    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    CorsConfiguration config = new CorsConfiguration();

    config.setAllowCredentials(true);
    config.setAllowedOrigins(List.of(
        "https://yourdomain.com",
        "https://app.yourdomain.com"
    ));
    config.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE", "OPTIONS"));
    config.setAllowedHeaders(List.of("*"));
    config.setExposedHeaders(List.of("Authorization"));
    config.setMaxAge(3600L);

    source.registerCorsConfiguration("/**", config);
    return new CorsFilter(source);
}

}

Rate Limiting

@Component public class RateLimitingFilter extends OncePerRequestFilter {

private final Cache&#x3C;String, AtomicInteger> requestCounts = Caffeine.newBuilder()
    .expireAfterWrite(1, TimeUnit.MINUTES)
    .build();

@Override
protected void doFilterInternal(HttpServletRequest request,
        HttpServletResponse response, FilterChain chain) throws Exception {

    String clientIP = getClientIP(request);
    AtomicInteger count = requestCounts.get(clientIP, k -> new AtomicInteger(0));

    if (count.incrementAndGet() > 100) {
        response.setStatus(HttpStatus.TOO_MANY_REQUESTS.value());
        response.getWriter().write("{\"error\": \"Rate limit exceeded\"}");
        return;
    }

    chain.doFilter(request, response);
}

private String getClientIP(HttpServletRequest request) {
    String xForwardedFor = request.getHeader("X-Forwarded-For");
    if (xForwardedFor != null &#x26;&#x26; !xForwardedFor.isEmpty()) {
        return xForwardedFor.split(",")[0].trim();
    }
    return request.getRemoteAddr();
}

}

Security Headers

@Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { return http // ... existing config .headers(headers -> headers .contentSecurityPolicy(csp -> csp .policyDirectives("default-src 'self'; frame-ancestors 'none'")) .frameOptions(frame -> frame.deny()) .xssProtection(xss -> xss.block(true)) .contentTypeOptions(Customizer.withDefaults()) .referrerPolicy(referrer -> referrer .policy(ReferrerPolicyHeaderWriter.ReferrerPolicy.STRICT_ORIGIN_WHEN_CROSS_ORIGIN))) .build(); }

Security Testing

@WebMvcTest(UserController.class) @Import(SecurityConfig.class) class UserControllerSecurityTest {

@Autowired
private MockMvc mockMvc;

@MockBean
private UserService userService;

@Test
void unauthenticated_shouldReturn401() throws Exception {
    mockMvc.perform(get("/api/v1/users"))
        .andExpect(status().isUnauthorized());
}

@Test
@WithMockUser(roles = "ADMIN")
void adminEndpoint_withAdminRole_shouldSucceed() throws Exception {
    mockMvc.perform(delete("/api/v1/admin/users/1"))
        .andExpect(status().isOk());
}

@Test
@WithMockUser(roles = "USER")
void adminEndpoint_withUserRole_shouldReturn403() throws Exception {
    mockMvc.perform(delete("/api/v1/admin/users/1"))
        .andExpect(status().isForbidden());
}

}

Monitoring Metrics

Metric Target

Failed auth attempts Monitor spikes

Token validation time < 5ms

Rate limit hits < 1%

Security exceptions 0 unhandled

Checklist

  • JWT secret from environment variable

  • Token expiration configured

  • Refresh token mechanism

  • CORS whitelist (no wildcards in prod)

  • Rate limiting enabled

  • Security headers configured

  • Method-level security (@PreAuthorize)

  • Password encoding (BCrypt)

  • HTTPS enforced

  • Security integration tests

When NOT to Use This Skill

  • Spring Boot application setup → Use spring-boot skill

  • OAuth2 server implementation → Use OAuth2-specific skill

  • General cryptography → Use security-expert skill

  • Database access → Use spring-data-jpa skill

  • REST API patterns → Use spring-web skill

Anti-Patterns

Anti-Pattern Why It's Bad Correct Approach

Hardcoded JWT secret Security risk Use environment variables

Disable CSRF without stateless Vulnerable to attacks Only disable with JWT (stateless)

Permit all in production No security Configure proper authorization

Store passwords in plain text Critical security flaw Use BCryptPasswordEncoder

No token expiration Tokens never invalidate Set proper expiration time

Allow all CORS origins CSRF vulnerability Whitelist specific origins

Quick Troubleshooting

Problem Likely Cause Solution

401 Unauthorized Token missing/invalid Check Authorization header format

403 Forbidden Insufficient permissions Check user roles and @PreAuthorize

CORS errors Origin not allowed Add origin to CORS configuration

Filter not executing Wrong filter order Check addFilterBefore placement

JWT parsing fails Wrong secret key Verify JWT_SECRET matches

Authentication null Filter not applied Ensure SecurityContextHolder is set

Further Reading

For advanced configurations: mcp__documentation__fetch_docs

  • Technology: spring-security , Topic: basics

  • Spring Security Docs

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

spring-security

No summary provided by upstream source.

Repository SourceNeeds Review
Security

spring-security

No summary provided by upstream source.

Repository SourceNeeds Review
Security

rust-security

No summary provided by upstream source.

Repository SourceNeeds Review