# spring-security-troubleshooter > Analyzes Spring Security logs to identify and resolve common authentication, authorization, and session-related failures (e.g., 403 Forbidden, 401 Unauthorized, CSRF issues). - Author: Jeongjin Kim - Repository: thecodinglog/spring-security-troubleshooting-claude-skills - Version: 20260127151549 - Stars: 0 - Forks: 0 - Last Updated: 2026-02-06 - Source: https://github.com/thecodinglog/spring-security-troubleshooting-claude-skills - Web: https://mule.run/skillshub/@@thecodinglog/spring-security-troubleshooting-claude-skills~spring-security-troubleshooter:20260127151549 --- --- name: spring-security-troubleshooter description: Analyzes Spring Security logs to identify and resolve common authentication, authorization, and session-related failures (e.g., 403 Forbidden, 401 Unauthorized, CSRF issues). --- # Spring Security Troubleshooting & Log Analysis Decode cryptic log patterns and pinpoint the root cause of authentication or authorization failures during development and testing. ## 1. Commands for Log Inspection ```bash # Run specific test with info-level logs and filter for security patterns ./gradlew test --tests "your.package.TestClass" --info 2>&1 | grep -E "(Pattern1|Pattern2|...)" | head -50 ``` --- ## 2. Common Error Patterns & Solutions ### A. CSRF Token Mismatch **Log Pattern:** > `Invalid CSRF token found for http://localhost:.../login` - **Cause:** POST/PUT/DELETE without a valid CSRF token while CSRF protection is enabled (default). - **Solution:** For testing or specific APIs, ignore the path: ```java .csrf(csrf -> csrf.ignoringRequestMatchers("/login", "/api/**")) ``` ### B. Missing Security Context in Session **Log Pattern:** > `No HttpSession currently exists` > `Did not find SecurityContext in HttpSession ... using the SPRING_SECURITY_CONTEXT session attribute` > `Created SecurityContextImpl [Null authentication]` - **Cause:** `SecurityContext` failed to persist or load from the session. Common in stateless APIs or misconfigured session management. - **Solution:** Ensure the context is explicitly saved or defaults are set: ```java .securityContext(Customizer.withDefaults()) ``` ### C. Fallback to Anonymous User **Log Pattern:** > `Set SecurityContextHolder to AnonymousAuthenticationToken [Principal=anonymousUser, ...]` > `Sending AnonymousAuthenticationToken ... to authentication entry point since access is denied` - **Cause:** No valid credentials; Spring treated the request as anonymous, which lacks required authorities. - **Checklist:** 1. Did the login request actually succeed? 2. Is the `JSESSIONID` cookie being passed back in subsequent requests? 3. Is `SecurityContextHolderFilter` present in your filter chain? ### D. Login Path Matching Failure **Log Pattern:** > `UsernamePasswordAuthenticationFilter : Did not match request to PathPattern [POST /login]` - **Cause:** Request didn’t hit the intended filter. Often when multiple `SecurityFilterChain` beans exist and an earlier one (different `@Order`) intercepted it. - **Checklist:** 1. Check `@Order` precedence. 2. Verify `securityMatcher()` patterns so the request is routed to the correct chain. ### E. 403 FORBIDDEN **Log Pattern:** > `expected: 201 CREATED but was: 403 FORBIDDEN` - **Verification Steps:** 1. **Authorities:** Does the user have the exact role (e.g. `ROLE_ADMIN`) required by `.hasRole()`? 2. **Persistence:** Is the user actually in the H2/Mock database? 3. **Profiles:** Is the correct `@ActiveProfiles` loaded? 4. **CSRF:** Is it a POST? (If so, re-check A.) --- ## 3. Essential Grep Patterns for Debugging | Focus Area | Grep Command Snippet | |---------------------|--------------------------------------------------------------------------------------| | **Full Security** | `grep -E "(SecurityContext|Session|JSESSIONID|authentication|ADMIN|anonymousUser|CSRF|403)"` | | **Login Process** | `grep -E "(POST /login|UsernamePassword|loadUserByUsername|authentication success|failed)"` | | **Environment** | `grep -E "(profile|Profile|active)"` | --- ## 4. Verifying the Filter Chain Check the log entry starting with `Will secure ... with filters:`. It shows which logic is applied to the request. **Key Filters:** - `CsrfFilter` — CSRF protection active? - `UsernamePasswordAuthenticationFilter` — form-login handler active? - `AuthorizationFilter` — final permission check present? --- ## 5. Rapid Debugging Workflow 1. **Capture Logs:** `./gradlew test --tests "MyTest" --info 2>&1 > debug.log` 2. **Check Profile:** `grep "profile is active" debug.log` (ensure Production isn’t used in Test). 3. **Check CSRF:** `grep -i "csrf" debug.log` 4. **Check Auth State:** `grep -E "(SecurityContext|Null authentication|anonymousUser)" debug.log` 5. **Trace Request:** `grep -E "(POST /login|Securing POST /login)" debug.log` --- ## 6. MockMvc: CSRF and Session in Tests For `MockMvc` tests, handle CSRF and session automatically: - Use `mockMvc.perform(post("/login").with(csrf()) ...)` when CSRF is enabled, or - Use `csrf().disable()` in the test `SecurityFilterChain` / `@AutoConfigureMockMvc(addFilters = false)` plus a custom chain for tests, or - Use `@WithMockUser` / `@WithUserDetails` when the endpoint requires an authenticated user instead of going through `/login`. When asked, help write a concrete MockMvc test that applies these choices to the project’s setup.