docs(handoff): logout-hardening verification notes

Records the automated outcomes (4/4 ITs pass, typecheck + build green)
and lists the three manual smoke tests still required from the SaaS
team — local-user, OIDC-user against Logto, stolen-token. The OIDC test
depends on Logto-side post_logout_redirect_uri registration; the others
can be exercised against any cameleer-server deployment.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
hsiegeln
2026-04-27 12:04:02 +02:00
parent 7837272a46
commit 463c6348b3

View File

@@ -72,6 +72,25 @@ If silent re-auth still happens after step 4, the most likely cause is that `pro
- Server ITs: `JwtRevocationIT`, `LogoutControllerIT` (both in `cameleer-server-app/src/test/java/com/cameleer/server/app/security/`) - Server ITs: `JwtRevocationIT`, `LogoutControllerIT` (both in `cameleer-server-app/src/test/java/com/cameleer/server/app/security/`)
- SaaS reference implementation: `cameleer-saas/ui/src/auth/useAuth.ts` (`@logto/react` `signOut(redirectUri)` + `cameleer:signed_out` sessionStorage flag pattern, mirrored here) - SaaS reference implementation: `cameleer-saas/ui/src/auth/useAuth.ts` (`@logto/react` `signOut(redirectUri)` + `cameleer:signed_out` sessionStorage flag pattern, mirrored here)
## Verification (filled in during Task 8) ## Verification
_Pending — see Task 8 of `docs/superpowers/plans/2026-04-27-logout-hardening.md` for the smoke-test results._ ### Automated (run on `feature/logout-hardening` HEAD `7837272a`, 2026-04-27)
| Check | Outcome |
|---|---|
| `JwtRevocationIT` (2 tests — revoked-token rejected, unrevoked-token accepted) | ✅ PASS |
| `LogoutControllerIT` (2 tests — authenticated logout revokes+audits+rejects subsequent calls; unauthenticated logout 204 no-op) | ✅ PASS |
| Reactor build | ✅ BUILD SUCCESS |
| `ui/ npm run typecheck` | ✅ 0 errors |
| `ui/ npm run build` | ✅ built in 1.21s (pre-existing chunk-size warning unchanged, unrelated) |
The pre-existing revocation-bug regression (token still works after logout) is now covered by `JwtRevocationIT.revokedTokenIsRejectedOnAuthenticatedRequest` and the end-to-end logout flow by `LogoutControllerIT.logoutRevokesTokensAuditsAndRejectsSubsequentCalls`. Both depend on the `JwtAuthenticationFilter` prefix-strip fix in commit `7066795c`.
### Manual — required from the SaaS team
- [ ] Register `https://<tenant-base-url>/login` as a `post_logout_redirect_uri` on the Logto application for each cameleer-server tenant (per the table above).
- [ ] Local-user smoke (in a browser): sign in → sign out → confirm 204 from `/api/v1/auth/logout` in DevTools Network tab → confirm "Signed out successfully" splash → "Sign in again" → confirm local form re-renders cleanly.
- [ ] OIDC-user smoke (in a browser, against Logto): sign in via SSO as user A → sign out → confirm top-level navigation through Logto's `end_session_endpoint` → land on splash → "Sign in again" → "Sign in with SSO" → confirm Logto **shows its login screen** (not silent re-auth) → sign in as user B → confirm dashboard reflects B (not A).
- [ ] Stolen-token smoke: copy `cameleer-access-token` from localStorage → sign out → confirm `curl -H "Authorization: Bearer <token>" .../api/v1/auth/me` returns 401.
The automated coverage proves the server-side revocation works. The manual checks prove the IdP-side session is also cleared and the UX flow is correct end-to-end.