feat(260606-tv8-01): add one-shot login-redirect helper + tests; fix client.ts comment

- Add loginRedirect.ts: maybeRedirectToLogin (sessionStorage one-shot guard) and
  clearLoginRedirect; guards window/sessionStorage for SSR/test safety
- Add loginRedirect.test.ts: covers first-call redirect, one-shot no-op, clear+retry
- Update client.ts: remove false claim that fetch follows Authelia 302 automatically;
  note that XHR/fetch CORS-blocks cross-origin redirects, top-level nav required
This commit is contained in:
Lucas Berger
2026-06-06 21:37:14 -04:00
parent 237ec493aa
commit 6dc9ccd2e9
3 changed files with 144 additions and 4 deletions
+9 -4
View File
@@ -5,8 +5,12 @@
* every cross-origin request (Vite dev proxy routes to :3000; production is
* same-origin via Pangolin).
*
* 401 responses mean the session has expired — the browser will follow the
* 302 redirect to Authelia on the next API call automatically (full-page nav).
* Auth note: the OIDC guard's 302 to Authelia is CORS-blocked for fetch/XHR —
* browsers do not follow cross-origin redirects from XHR to an external IdP.
* Re-authentication therefore requires a TOP-LEVEL navigation to /api/login
* (see apps/pwa/src/lib/loginRedirect.ts). fetchMe and other fetch calls here
* are pure data fetches; they throw on non-ok responses and leave the redirect
* decision to the caller (CalendarShell via maybeRedirectToLogin).
*/
// ── /api/me ────────────────────────────────────────────────────────────────
@@ -27,8 +31,9 @@ export async function fetchMe(): Promise<MeResponse> {
})
if (!res.ok) {
// 302 → browser follows redirect to Authelia automatically.
// For 4xx/5xx, throw so React Query can surface the error.
// Throw on any non-ok response. The OIDC guard's 302 to Authelia cannot be
// followed by fetch (CORS-blocked for XHR). Callers that handle auth errors
// should use maybeRedirectToLogin() for a top-level navigation to /api/login.
throw new Error(`GET /api/me failed: ${res.status}`)
}