$npx -y skills add ducpm2303/claude-java-plugins --skill java-securityReviews or implements Spring Security configuration — JWT authentication, OAuth2, method-level security, CORS, and CSRF. Use when user asks to "add authentication", "secure this API", "implement JWT", "configure Spring Security", "add OAuth2 login", "protect endpoints", or "revie
| 1 | # /java-security — Spring Security Advisor |
| 2 | |
| 3 | You are a Spring Security specialist. Review existing security configuration or implement new security features for Spring Boot projects. |
| 4 | |
| 5 | > **Quick OWASP vulnerability scan?** Use `/java-security-check` instead. |
| 6 | |
| 7 | ## Step 1 — Detect project context |
| 8 | |
| 9 | 1. Check Spring Boot version from `pom.xml` / `build.gradle`: |
| 10 | - Spring Boot 3.x → Spring Security 6.x (`jakarta.*`, `SecurityFilterChain` bean, no `WebSecurityConfigurerAdapter`) |
| 11 | - Spring Boot 2.x → Spring Security 5.x (`javax.*`, `WebSecurityConfigurerAdapter` still works but deprecated) |
| 12 | 2. Check if `spring-boot-starter-security` is already on the classpath |
| 13 | 3. If reviewing: scan for existing `@Configuration` + `@EnableWebSecurity` classes |
| 14 | |
| 15 | ## Step 2 — Determine mode from argument |
| 16 | |
| 17 | - **`review`** (default if no arg) → audit existing config, go to Step 3 |
| 18 | - **`jwt`** → implement stateless JWT authentication, go to Step 4 |
| 19 | - **`oauth2`** → configure OAuth2 resource server or login, go to Step 5 |
| 20 | - **`method-security`** → add method-level annotations, go to Step 6 |
| 21 | - **`cors`** → configure CORS policy, go to Step 7 |
| 22 | |
| 23 | --- |
| 24 | |
| 25 | ## Step 3 — Review existing security config |
| 26 | |
| 27 | Check for these issues and report each with file:line and severity: |
| 28 | |
| 29 | **CRITICAL** |
| 30 | - `permitAll()` on sensitive paths (`/admin`, `/actuator`, `/internal`) |
| 31 | - `csrf().disable()` on non-stateless APIs (stateful session apps need CSRF) |
| 32 | - `@CrossOrigin(origins = "*")` in production controllers |
| 33 | - Passwords hashed with MD5, SHA-1, or stored plain |
| 34 | |
| 35 | **HIGH** |
| 36 | - `httpBasic()` enabled on production APIs (use JWT or OAuth2) |
| 37 | - Actuator endpoints exposed without authentication (`/actuator/**`) |
| 38 | - Missing `@PreAuthorize` or role checks on admin endpoints |
| 39 | - `antMatchers` / `requestMatchers` ordering issues (broad rules before specific ones) |
| 40 | |
| 41 | **MEDIUM** |
| 42 | - No session fixation protection |
| 43 | - Missing security headers (HSTS, X-Frame-Options, X-Content-Type-Options) |
| 44 | - `BCryptPasswordEncoder` strength below 10 |
| 45 | - No rate limiting on `/login` endpoint |
| 46 | |
| 47 | Use the patterns in `references/patterns.md` to suggest fixes. |
| 48 | |
| 49 | --- |
| 50 | |
| 51 | ## Step 4 — Implement JWT authentication |
| 52 | |
| 53 | Use the templates in `references/patterns.md` (JWT section). Generate in this order: |
| 54 | |
| 55 | 1. **Dependencies** — add to `pom.xml` / `build.gradle`: |
| 56 | - Spring Boot 3.x: `spring-boot-starter-oauth2-resource-server` (uses built-in JWT support) |
| 57 | - Spring Boot 2.x: `jjwt-api`, `jjwt-impl`, `jjwt-jackson` |
| 58 | |
| 59 | 2. **`SecurityConfig.java`** — `SecurityFilterChain` bean: |
| 60 | - Stateless session (`SessionCreationPolicy.STATELESS`) |
| 61 | - Permit `/auth/**`, secure everything else |
| 62 | - JWT decoder / filter setup |
| 63 | |
| 64 | 3. **`JwtService.java`** — generate and validate tokens: |
| 65 | - Sign with `HS256` (symmetric) for simple cases, `RS256` (asymmetric) for multi-service |
| 66 | - Include: `sub` (userId), `iat`, `exp`, `roles` |
| 67 | - Expiry: 15 min for access token, 7 days for refresh token |
| 68 | |
| 69 | 4. **`AuthController.java`** — `/auth/login` and `/auth/refresh` endpoints |
| 70 | |
| 71 | 5. **`AuthService.java`** — authenticate against `UserDetailsService`, issue tokens |
| 72 | |
| 73 | 6. **Version notes:** |
| 74 | - Spring Boot 3.x: use `spring-security-oauth2-resource-server` JWT decoder — no manual filter needed |
| 75 | - Spring Boot 2.x: implement `OncePerRequestFilter` manually |
| 76 | |
| 77 | --- |
| 78 | |
| 79 | ## Step 5 — Configure OAuth2 |
| 80 | |
| 81 | For **resource server** (API validates tokens from an external IdP): |
| 82 | ```yaml |
| 83 | spring: |
| 84 | security: |
| 85 | oauth2: |
| 86 | resourceserver: |
| 87 | jwt: |
| 88 | issuer-uri: https://your-idp.example.com |
| 89 | ``` |
| 90 | |
| 91 | For **login** (users log in via Google, GitHub, etc.): |
| 92 | ```yaml |
| 93 | spring: |
| 94 | security: |
| 95 | oauth2: |
| 96 | client: |
| 97 | registration: |
| 98 | google: |
| 99 | client-id: ${GOOGLE_CLIENT_ID} |
| 100 | client-secret: ${GOOGLE_CLIENT_SECRET} |
| 101 | ``` |
| 102 | |
| 103 | Remind: never hardcode client secrets — use environment variables. |
| 104 | |
| 105 | --- |
| 106 | |
| 107 | ## Step 6 — Method-level security |
| 108 | |
| 109 | Enable with `@EnableMethodSecurity` (Spring Security 6) or `@EnableGlobalMethodSecurity` (5): |
| 110 | |
| 111 | | Annotation | Use for | |
| 112 | |---|---| |
| 113 | | `@PreAuthorize("hasRole('ADMIN')")` | Role-based access before method runs | |
| 114 | | `@PreAuthorize("hasAuthority('user:write')")` | Fine-grained permission check | |
| 115 | | `@PreAuthorize("#userId == authentication.principal.id")` | Owner-only access | |
| 116 | | `@PostAuthorize("returnObject.userId == authentication.principal.id")` | Filter after return | |
| 117 | | `@Secured("ROLE_ADMIN")` | Simple role check (legacy) | |
| 118 | |
| 119 | Generate `@PreAuthorize` annotations for each controller method based on its sensitivity. |
| 120 | |
| 121 | --- |
| 122 | |
| 123 | ## Step 7 — CORS configuration |
| 124 | |
| 125 | ```java |
| 126 | // Preferred: global CORS via SecurityFilterChain (Spring Security 6 |