- Shipped
- June 15, 2026 at 6:58 PM UTC
- Author
- kamo
- Commit
- 896ea51
The session id lived in a browser cookie shared across all tabs of an origin, so a second tab (impersonation) could not hold its own session. Move the carrier to sessionStorage (per-tab): - sessionClient: token helpers + a global fetch wrapper that attaches the id as X-***-Token on same-origin /api calls, plus a one-time cookie->sessionStorage migration. Installed via SessionBootstrap in layout. - **************** header-first (cookie fallback) used by generate-otk, session/info, session/extend, logout, meet/invite-email. - generateOTK + getKsemIdFromRequest prefer X-***-Token over the cookie. - /api/validate no longer sets a *** cookie; returns the id and the /validate page stores it in this tab's sessionStorage. - useUserInfo + all WebSocket hooks read the id from sessionStorage. - logout captures the token before clearing storage so the Redis session is still invalidated. Impersonation now just opens /validate?otk=... in a new tab (same pathway as login: Redis session created server-side, OTK handed to /validate); the new tab gets its own session and the admin tab is untouched. Removes the obsolete keepPrev/ImpersonationBanner return-to-admin machinery. Orgs remain separated by domain — unchanged.