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 Java templates
Modern Java Rules
Java 21+ defaults: records, sealed types, pattern matching, virtual threads, var.
Java Testing with JUnit 5
JUnit 5 + AssertJ + Mockito + Testcontainers — opinionated test conventions.
Java Virtual Threads & Concurrency
Project Loom virtual threads, structured concurrency, and modern concurrent patterns.
Java Build (Maven & Gradle)
Build conventions, dependency management, multi-module projects, and CI patterns.
Java Streams & Collections
Streams API, immutable collections, Collectors, and idiomatic data manipulation.