Web Worker & Tabs
How @mrzr/api-client keeps access tokens inside a Web Worker away from XSS, when it falls back to the main thread, and how tabs share login and logout.
Tokens live in a Web Worker
By default every request runs inside a Web Worker. The token is stored there and attached there, so page JavaScript, including a script injected through XSS, can't read it.
Where is the token?
Log in, then search everywhere page JavaScript (or an injected script) could look for the token.
Not checked yet.
There is nothing to set up: the worker is bundled inline, with no extra file to host and no bundler plugin to add.
When it falls back
The client silently uses the main thread instead, with identical behaviour, when:
- you pass
worker: false, or the code runs on a server (SSR, Node) - the browser blocks the worker. Your Content Security Policy must allow
worker-src 'self' blob: extractTokensorbuildRefreshBodyis a function. Functions can't be sent into a worker; use their object forms
Check what you got with api.isWorker.
What it can't protect
An injected script can still use your session. It can call api.get(...) just like your own code, so worker isolation stops token theft, not XSS itself. Also, storage: "local", "session" and "cookie" put the token where page JavaScript can read it. Keep the default "memory" to get the full benefit.
Tabs stay in sync
Clients with the same storageKey talk to each other over BroadcastChannel:
- Log out in one tab: every tab logs out.
- Log in in one tab: the others pick up the session (when storage is shared:
"local"or"cookie"). - Refresh: tabs that share a session take turns through the Web Locks API. When one tab has already refreshed, the next adopts its new tokens instead of spending the refresh token again. This matters when your server rotates refresh tokens and treats reuse as theft.
Two independent apps on one origin? Give each its own storageKey:
const adminApi = createClient({ storageKey: "admin" });
const shopApi = createClient({ storageKey: "shop" });Turn syncing off with multiTab: false.
Uploads & Downloads
Upload FormData, File, Blob and binary bodies with @mrzr/api-client, keep long uploads from failing on token expiry, and download files as a Blob.
WebSockets & Socket.io
Authenticate WebSocket and socket.io connections with @mrzr/api-client using a short-lived socket ticket, without exposing the access token to the page.