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.
A socket needs a credential too. There are two ways to give it one.
Recommended: a ticket from your server
Add an endpoint that returns a short-lived, single-use ticket for the socket. api.getSocketToken(url) calls it as a normal authenticated request (token attached, refreshed on 401) and returns only the ticket. The access token never leaves the worker.
import { io } from "socket.io-client";
const socket = io("https://realtime.example.com", {
// A function, so every reconnect gets a fresh ticket.
auth: async (cb) => cb({ token: await api.getSocketToken("/auth/socket-ticket") }),
});A plain WebSocket can't set headers, so pass the ticket in the URL:
const ticket = await api.getSocketToken("/auth/socket-ticket");
const ws = new WebSocket(`wss://realtime.example.com/?ticket=${encodeURIComponent(ticket)}`);The endpoint is called with POST (pass { method: "GET" } to change that) and may return the ticket as a plain string or as { token }, { ticket } or { socketToken }, optionally inside { data }.
Opt-in: the access token itself
If the socket server only accepts your API token, enable exposeTokens:
const api = createClient({ baseUrl, exposeTokens: true });
const socket = io(URL, {
auth: async (cb) => cb({ token: await api.getAccessToken() }),
});getAccessToken() refreshes first when the token is about to expire. The trade-off: any script on the page can now read the token. Use the ticket when you can.
Reconnect when the session changes
api.onAuthStateChange((state) => {
if (!state.isAuthenticated) socket.disconnect();
else if (socket.connected) socket.disconnect().connect(); // fetches a new ticket
});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.
Plugins
Extend @mrzr/api-client with plugins. Call several APIs on one session with the services plugin, or write your own with four small hooks.