# Authentication & Authorization Invariants — auth-migration ## 1. Authentication Rules | ID | Rule | Trigger | Expected Behavior | Error Code | |----|------|---------|-------------------|------------| | AUTH-001 | JWT must contain `sub` claim | Any protected endpoint | Reject with 401 if `sub` missing/empty | `AUTH_MISSING_SUB` | | AUTH-002 | JWT `exp` must be in future | Any protected endpoint | Reject with 401 if expired | `AUTH_TOKEN_EXPIRED` | | AUTH-003 | JWT signature must verify against secret | Any protected endpoint | Reject with 401 if signature invalid | `AUTH_INVALID_SIGNATURE` | | AUTH-004 | Bearer token required in Authorization header | Any protected endpoint | Reject with 401 if header missing | `AUTH_MISSING_TOKEN` | | AUTH-005 | Token format must be `Bearer ` | Any protected endpoint | Reject with 401 if malformed | `AUTH_MALFORMED_TOKEN` | ## 2. Authorization Rules | ID | Rule | Scope | Expected Behavior | Error Code | |----|------|-------|-------------------|------------| | AUTH-010 | ADMIN role required for user management | `/api/admin/**` | Reject with 403 if not ADMIN | `AUTH_FORBIDDEN_ADMIN` | | AUTH-011 | Resource owner or ADMIN can modify | `/api/users/{id}/**` | Reject with 403 if neither | `AUTH_FORBIDDEN_RESOURCE` | | AUTH-012 | Any authenticated user can read public profiles | `/api/users/public/**` | Allow 200 if authenticated | — | | AUTH-013 | Role hierarchy: ADMIN > MANAGER > USER | All role-gated endpoints | Higher role inherits lower permissions | — | ## 3. Error Response Schema | HTTP Status | Error Code | Response Body Shape | |-------------|------------|---------------------| | 401 | `AUTH_MISSING_TOKEN` | `{"error":"AUTH_MISSING_TOKEN","message":"Authorization header required","timestamp":}` | | 401 | `AUTH_MALFORMED_TOKEN` | `{"error":"AUTH_MALFORMED_TOKEN","message":"Bearer token format required","timestamp":}` | | 401 | `AUTH_TOKEN_EXPIRED` | `{"error":"AUTH_TOKEN_EXPIRED","message":"Token has expired","timestamp":}` | | 401 | `AUTH_INVALID_SIGNATURE` | `{"error":"AUTH_INVALID_SIGNATURE","message":"Token signature verification failed","timestamp":}` | | 401 | `AUTH_MISSING_SUB` | `{"error":"AUTH_MISSING_SUB","message":"Token missing subject claim","timestamp":}` | | 403 | `AUTH_FORBIDDEN_ADMIN` | `{"error":"AUTH_FORBIDDEN_ADMIN","message":"Admin role required","timestamp":}` | | 403 | `AUTH_FORBIDDEN_RESOURCE` | `{"error":"AUTH_FORBIDDEN_RESOURCE","message":"Not authorized for this resource","timestamp":}` | ## 4. Session / Cookie Semantics | ID | Rule | Behavior | |----|------|----------| | SESS-001 | Session cookie `HttpOnly` | Must be `true` | | SESS-002 | Session cookie `Secure` | Must be `true` in production | | SESS-003 | Session cookie `SameSite` | Must be `Lax` or `Strict` | | SESS-004 | CSRF token required for state-changing ops | POST/PUT/DELETE without CSRF → 403 | ## 5. Migration Checklist - [ ] Spring Security filter chain preserves order: JWT filter before session filter - [ ] `@PreAuthorize` annotations match existing role-gate logic - [ ] `AuthenticationEntryPoint` returns exact error schema (AUTH_* codes) - [ ] `AccessDeniedHandler` returns exact error schema (AUTH_FORBIDDEN_* codes) - [ ] Cookie attributes (`HttpOnly`, `Secure`, `SameSite`) set via `CookieSecurityConfigurer` - [ ] CSRF protection enabled for state-changing endpoints - [ ] Role hierarchy bean `RoleHierarchyImpl` wired with ADMIN > MANAGER > USER