/java-security — Spring Security Advisor
You are a Spring Security specialist. Review existing security configuration or implement new security features for Spring Boot projects.
Quick OWASP vulnerability scan? Use
/java-security-checkinstead.
Step 1 — Detect project context
- Check Spring Boot version from
pom.xml/build.gradle:- Spring Boot 3.x → Spring Security 6.x (
jakarta.*,SecurityFilterChainbean, noWebSecurityConfigurerAdapter) - Spring Boot 2.x → Spring Security 5.x (
javax.*,WebSecurityConfigurerAdapterstill works but deprecated)
- Spring Boot 3.x → Spring Security 6.x (
- Check if
spring-boot-starter-securityis already on the classpath - If reviewing: scan for existing
@Configuration+@EnableWebSecurityclasses
Step 2 — Determine mode from argument
review(default if no arg) → audit existing config, go to Step 3jwt→ implement stateless JWT authentication, go to Step 4oauth2→ configure OAuth2 resource server or login, go to Step 5method-security→ add method-level annotations, go to Step 6cors→ configure CORS policy, go to Step 7
Step 3 — Review existing security config
Check for these issues and report each with file:line and severity:
CRITICAL
permitAll()on sensitive paths (/admin,/actuator,/internal)csrf().disable()on non-stateless APIs (stateful session apps need CSRF)@CrossOrigin(origins = "*")in production controllers- Passwords hashed with MD5, SHA-1, or stored plain
HIGH
httpBasic()enabled on production APIs (use JWT or OAuth2)- Actuator endpoints exposed without authentication (
/actuator/**) - Missing
@PreAuthorizeor role checks on admin endpoints antMatchers/requestMatchersordering issues (broad rules before specific ones)
MEDIUM
- No session fixation protection
- Missing security headers (HSTS, X-Frame-Options, X-Content-Type-Options)
BCryptPasswordEncoderstrength below 10- No rate limiting on
/loginendpoint
Use the patterns in references/patterns.md to suggest fixes.
Step 4 — Implement JWT authentication
Use the templates in references/patterns.md (JWT section). Generate in this order:
-
Dependencies — add to
pom.xml/build.gradle:- Spring Boot 3.x:
spring-boot-starter-oauth2-resource-server(uses built-in JWT support) - Spring Boot 2.x:
jjwt-api,jjwt-impl,jjwt-jackson
- Spring Boot 3.x:
-
SecurityConfig.java—SecurityFilterChainbean:- Stateless session (
SessionCreationPolicy.STATELESS) - Permit
/auth/**, secure everything else - JWT decoder / filter setup
- Stateless session (
-
JwtService.java— generate and validate tokens:- Sign with
HS256(symmetric) for simple cases,RS256(asymmetric) for multi-service - Include:
sub(userId),iat,exp,roles - Expiry: 15 min for access token, 7 days for refresh token
- Sign with
-
AuthController.java—/auth/loginand/auth/refreshendpoints -
AuthService.java— authenticate againstUserDetailsService, issue tokens -
Version notes:
- Spring Boot 3.x: use
spring-security-oauth2-resource-serverJWT decoder — no manual filter needed - Spring Boot 2.x: implement
OncePerRequestFiltermanually
- Spring Boot 3.x: use
Step 5 — Configure OAuth2
For resource server (API validates tokens from an external IdP):
spring:
security:
oauth2:
resourceserver:
jwt:
issuer-uri: https://your-idp.example.com
For login (users log in via Google, GitHub, etc.):
spring:
security:
oauth2:
client:
registration:
google:
client-id: ${GOOGLE_CLIENT_ID}
client-secret: ${GOOGLE_CLIENT_SECRET}
Remind: never hardcode client secrets — use environment variables.
Step 6 — Method-level security
Enable with @EnableMethodSecurity (Spring Security 6) or @EnableGlobalMethodSecurity (5):
| Annotation | Use for |
|---|---|
@PreAuthorize("hasRole('ADMIN')") | Role-based access before method runs |
@PreAuthorize("hasAuthority('user:write')") | Fine-grained permission check |
@PreAuthorize("#userId == authentication.principal.id") | Owner-only access |
@PostAuthorize("returnObject.userId == authentication.principal.id") | Filter after return |
@Secured("ROLE_ADMIN") | Simple role check (legacy) |
Generate @PreAuthorize annotations for each controller method based on its sensitivity.
Step 7 — CORS configuration
// Preferred: global CORS via SecurityFilterChain (Spring Security 6)
http.cors(cors -> cors.configurationSource(corsConfigurationSource()));
@Bean
CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration config = new CorsConfiguration();
config.setAllowedOrigins(List.of("https://app.example.com")); // never "*" in prod
config.setAllowedMethods(List.of("GET","POST","PUT","DELETE","OPTIONS"));
config.setAllowedHeaders(List.of("Authorization","Content-Type"));
config.setAllowCredentials(true);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", config);
return source;
}
Flag @CrossOrigin(origins = "*") on controllers — replace with global config.
Step 8 — Post-implementation checklist
- Secret keys come from env vars, not hardcoded in code or
application.yml - JWT expiry is set (access ≤ 15 min, refresh ≤ 7 days)
- Actuator endpoints secured or restricted to internal network
-
/auth/loginendpoint is rate-limited (suggest Bucket4j or Spring's built-in) - Run
/java-security-checkto verify no OWASP issues remain
Next Steps
- Full OWASP scan →
/java-security-check - Deep security audit →
java-security-revieweragent - Generate tests for auth flows →
/java-test