Authentication
Log users in with bearer tokens or httpOnly cookies. Choose where tokens are stored, restore a cookie session on page load and enable CSRF protection.
The client owns the tokens. You never set an Authorization header or read storage yourself.
Two modes
authMode: "header" (default) | authMode: "cookie" | |
|---|---|---|
| How the credential travels | Authorization: Bearer <token> | httpOnly cookie set by your server |
| Can page JavaScript read it? | No, in worker mode | No |
| Needs CSRF protection? | No | Yes |
| Good for | SPAs and APIs on another domain | Apps where you control the backend |
Header mode
const api = createClient({ baseUrl: "https://api.example.com" });
await api.login({ email, password }); // tokens captured from the response
await api.get("/me"); // Authorization: Bearer … attached
await api.logout();The token is only ever sent to the baseUrl origin and the page's own origin. To send it to another API of yours, list that origin:
createClient({ baseUrl, authOrigins: ["https://files.example.com"] });Already have tokens, for example from an OAuth callback or SSR? Seed them with api.setTokens({ accessToken, refreshToken }).
Where tokens are stored
storage | Survives reload | Readable by page JS |
|---|---|---|
"memory" (default) | No | No: the token never leaves the worker |
"session" | Same tab only | Yes |
"local" | Yes | Yes |
"cookie" | Yes (readable cookie, not httpOnly) | Yes |
"memory" is the safest option. The user logs in again after a reload, unless the refresh token survives in an httpOnly cookie on your server. You can also pass your own adapter: any object with get, set and clear.
Cookie mode
Your server sets HttpOnly; Secure cookies at login. The client never sees a token. It just sends requests with credentials: "include".
const api = createClient({
baseUrl: "https://api.example.com",
authMode: "cookie",
xsrfCookieName: "csrftoken", // see CSRF below
});JavaScript can't see httpOnly cookies, so after a page reload the client doesn't know whether a session exists. Ask the server once on startup:
const { isAuthenticated, user } = await api.restoreSession("/auth/me");Without a URL, restoreSession() tries the refresh endpoint instead.
CSRF
With cookies, a malicious site can make the browser send your cookie along with a forged request. The standard defence is the double-submit pattern: the server sets a readable CSRF cookie, and the client copies its value into a header.
createClient({ authMode: "cookie", xsrfCookieName: "csrftoken" });
// POST/PUT/PATCH/DELETE and refresh → X-CSRF-Token: <cookie value>If the token isn't in a cookie (for example it's in a <meta> tag), use getCsrfToken: () => … instead. Your server must still compare the header with the cookie and reject mismatches.
Auth state
const state = await api.getAuthState(); // { isAuthenticated, expiresAt, user }
const off = api.onAuthStateChange((state) => { /* … */ });The state never contains tokens. onAuthFailure in the client options fires when the session is gone for good: the refresh endpoint rejected it (401/403), or the user logged out in any tab.
Requests & Errors
Make GET, POST, PUT, PATCH and DELETE requests with @mrzr/api-client, build URLs and query strings, read the response and handle ApiError.
Token Refresh
How @mrzr/api-client refreshes access tokens automatically, sends one refresh for many concurrent 401s, and how to map custom token response shapes.