Spring Security Rules
SecurityFilterChain (no WebSecurityConfigurerAdapter), OAuth2 resource server, JWT.
# CLAUDE.md — Spring Security
## Configuration
- Use the modern `SecurityFilterChain` bean approach. The deprecated `WebSecurityConfigurerAdapter` is gone.
- One `@Bean SecurityFilterChain` per filter chain. Multiple chains for `/api/**` vs `/admin/**` if their auth differs.
- Configure with the lambda DSL:
```java
http.authorizeHttpRequests(auth -> auth
.requestMatchers("/public/**").permitAll()
.requestMatchers("/admin/**").hasRole("ADMIN")
.anyRequest().authenticated()
);
```
- Always end with `.anyRequest().authenticated()` (or `.denyAll()`). Default-allow is a foot-gun.
## Method security
- Enable with `@EnableMethodSecurity`. Use `@PreAuthorize` on service methods.
- `@PreAuthorize("hasRole('ADMIN')")` for role checks. Use SpEL for object-level: `@PreAuthorize("#user.id == authentication.name")`.
- Don't put auth checks in controllers. They live at the service boundary so non-HTTP callers (jobs, schedulers) get them too.
## Password handling
- `BCryptPasswordEncoder` with cost factor 12+. Re-evaluate yearly.
- Or `Argon2PasswordEncoder` if starting fresh.
- Use `DelegatingPasswordEncoder` (`PasswordEncoderFactories.createDelegatingPasswordEncoder()`) to support migration between algorithms.
- Never log raw passwords. Configure your error reporter to filter.
## OAuth2 Resource Server
- For JWT-protected APIs:
```java
http.oauth2ResourceServer(oauth2 -> oauth2.jwt(jwt -> jwt.jwkSetUri(jwksUri)));
```
- Configure `JwtAuthenticationConverter` to map claims to authorities. Don't roll your own JWT validation.
- Validate `iss`, `aud`, and `exp` — set them in your authorization server, verify them here.
## CSRF
- Default-on for browser apps. Disable only for stateless APIs:
```java
http.csrf(AbstractHttpConfigurer::disable);
```
- For session-based forms, use the cookie-based token strategy (`CookieCsrfTokenRepository`).
- Never disable CSRF on session-authenticated endpoints that mutate state.
## CORS
- Use `CorsConfigurationSource` bean. Define an explicit allowlist — never `allowedOrigins("*")` with `allowCredentials(true)` (Spring will refuse).
- Configure once globally for cross-origin APIs. Don't sprinkle `@CrossOrigin` on controllers.
## Session management
- Stateless APIs: `http.sessionManagement(sm -> sm.sessionCreationPolicy(STATELESS))`.
- Stateful (server-rendered): default is fine. Set `maximumSessions` and `expiredUrl` for fixed concurrency.
- Always invalidate sessions on logout: `http.logout(logout -> logout.invalidateHttpSession(true).deleteCookies("JSESSIONID"))`.
## Don't
- Don't put `permitAll()` on `**/*` to "fix" auth for now. The fix becomes permanent.
- Don't store auth tokens in `localStorage` from server-rendered Spring apps. HttpOnly cookies are the answer.
- Don't write your own `UserDetailsService` if Spring's defaults plus a JPA-backed one cover you.
- Don't expose actuator endpoints (`/actuator/**`) without auth. They leak everything.
Other Spring templates
Spring Framework Core Rules
Dependency injection, bean lifecycle, configuration classes, and profiles.
Spring Data JPA
Repositories, derived queries, custom JPQL, projections, and N+1 prevention.
Spring MVC Rules
Controllers, ResponseEntity, validation, exception handling, and content negotiation.
Spring WebFlux (Reactive)
Reactive Spring with Mono/Flux, R2DBC, backpressure, and non-blocking patterns.
Spring Boot 3 Modern Rules
Boot 3+ defaults: starters, configuration properties, profiles, and structured logging.