feat(auth): per-tab account — different account per browser tab
Two tabs in one browser can now run two different signed-in accounts at once. - The signed session cookie stays the browser's account WALLET (account_ids). Which account a given tab acts as is a per-tab choice held in sessionStorage and sent per-request via the X-Siftlode-Account header; current_user honours it only for an account already in the wallet, without mutating the cookie's default account. Switching accounts sets the header + reloads THIS tab only, instead of the old cookie-wide switch that changed every tab. - WebSocket can't send headers, so the per-tab account rides in the ?account= query param (validated against the wallet). - Logout is per-tab aware: it signs the requesting tab's active account out of the wallet (promoting a new default only if the removed one was the default), and the tab drops its override. A stale per-tab header account 401s just that tab instead of clearing the session. - Serve index.html with Cache-Control: no-cache so a deploy's new hashed bundle is picked up immediately instead of the browser running a heuristically-cached stale index.html.
This commit is contained in:
parent
c0487101fe
commit
5cd807ec51
6 changed files with 146 additions and 36 deletions
|
|
@ -2,7 +2,7 @@
|
|||
// to all of a user's open tabs when a message is stored; subscribers react (e.g. refetch the
|
||||
// thread + conversations). Auto-reconnects with backoff; a low-frequency poll elsewhere is the
|
||||
// safety net if the socket is down.
|
||||
import type { Message, MessageUser } from "./api";
|
||||
import { getActiveAccount, type Message, type MessageUser } from "./api";
|
||||
|
||||
// A pushed message plus both parties, so the dock can open/flash the right window.
|
||||
export interface IncomingMessage {
|
||||
|
|
@ -20,7 +20,11 @@ let reconnectTimer: ReturnType<typeof setTimeout> | null = null;
|
|||
|
||||
function url(): string {
|
||||
const proto = location.protocol === "https:" ? "wss" : "ws";
|
||||
return `${proto}://${location.host}/api/messages/ws`;
|
||||
// A WebSocket can't carry the X-Siftlode-Account header, so the per-tab account rides in the
|
||||
// query string (validated against the browser wallet server-side).
|
||||
const account = getActiveAccount();
|
||||
const qs = account != null ? `?account=${account}` : "";
|
||||
return `${proto}://${location.host}/api/messages/ws${qs}`;
|
||||
}
|
||||
|
||||
function open() {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue