Skip to content

feat(admin-ui): a stale cookie sends you to sign in (STORY-475) - #840

Merged
genwave-radio merged 1 commit into
mainfrom
admin-ui/api-fetch-401-475
Sep 23, 2026
Merged

genwave-radio merged 1 commit into
mainfrom
admin-ui/api-fetch-401-475

Conversation

@genwave-radio

Copy link
Copy Markdown
Collaborator

🧭 What

PR-7 of the launch-polish epic (STORY-475, gh-#729), shipping in v5.13.0.

  • One wrapper owns 401 (T566): admin-ui/lib/api-fetch.ts. On a 401 it posts /api/auth/logout to clear the HttpOnly genwave-auth cookie, then does a full page load to /login?expired=1. Its promise never settles, so no error toast flashes before the page leaves. Any other non-ok status rejects with the Response.
  • The four lib 401 branches are gone: broadcast-api, use-row-patch, persona-taste-api and station-thumb-api now call apiFetch. Every non-401 outcome and message is unchanged.
  • About page (server component): a 401 redirects to the new /session-expired route. That route clears the cookie and sends the browser to /login?expired=1, using a relative redirect so it works on any host name.
  • Login page: with ?expired=1 it shows "Your session ended. Sign in again."
  • middleware.ts is unchanged; it still only checks that the cookie exists.

Closes #729

✅ Verified

  • Tests: admin-ui tsc, typecheck:specs, lint (0 errors), jest (129 suites, 1368 passed) and next build all pass. A spec scans the source and fails on any 401 comparison or case 401 outside lib/api-fetch.ts.
  • Built image on the dev station:
Path Result
Signed in, cookie swapped for a junk value, click Never play on a catalog row Lands on /login?expired=1 with "Your session ended. Sign in again."; the cookie is gone
GET /about with a junk cookie 307 to /session-expired
GET /session-expired with Host: genwave.local 307 Location: /login?expired=1; Set-Cookie: genwave-auth=; Path=/; Max-Age=0

⚠️ Notes

  • Restarting api does not end a session. The key ring is kept on the dp_keys volume by design, so the wire test used a junk cookie instead.
  • Low: /session-expired is a GET that signs you out, so another site can link you into being signed out. Nothing is exposed and no server state changes. A Sec-Fetch-Site check could harden it later.
  • Other pages: other fetch call sites don't use apiFetch yet, so a 401 there still shows each page's own error. This PR moves only the five former 401 sites.

lib/api-fetch.ts: a 401 posts /api/auth/logout (the cookie is HttpOnly),
hard-navigates to /login?expired=1 and never settles; other non-ok
statuses reject with the Response. The four lib 401 branches are gone.
The About server component redirects to /session-expired, a route that
clears genwave-auth and 307s to a relative /login?expired=1. The login
page reads the flag. middleware.ts is unchanged (F208.2).
@genwave-radio
genwave-radio merged commit 8309208 into main Sep 23, 2026
11 checks passed
@genwave-radio
genwave-radio deleted the admin-ui/api-fetch-401-475 branch September 23, 2026 23:30
@github-actions github-actions Bot locked and limited conversation to collaborators Sep 23, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

admin-ui: a session cookie from before an api restart renders "Unable to load the ads library." instead of sending the operator back to sign-in

1 participant