SSR sessions
Own token cookies and refresh concurrency safely in server-rendered applications.
A
JUse @cavuno/board/server for session-cookie encoding and single-flight refresh patterns. The app, not the shared SDK client, owns each user’s tokens.
Why the server client uses nostore
A module-scoped server client can serve many users. It must never persist one user’s access token in shared SDK storage. Configure storage: 'nostore', keep the bearer pair in Cavuno’s httpOnly session cookie, and pass the current access token on each private call.
createSessionRefresher fails during construction when a server client uses persistent storage. That failure prevents a cross-user token leak rather than silently accepting an unsafe configuration.
Read and refresh a session
The helpers consume and return cookie header strings, so the same logic can be connected to Next.js, TanStack Start, Remix, or a Worker response.
Attach setCookie to the framework response only when it is non-null. In a multi-board host, pass the same { board: identifier } option to parseSessionCookie, serializeSessionCookie, and clearSessionCookie so sessions cannot collide.
Verify the flow
- Log in, reload, and confirm the account remains authenticated.
- Force the access token near expiry and issue concurrent private reads. They must share one in-process refresh and receive the rotated cookie.
- Revoke or corrupt the refresh token. The next request must clear the cookie and continue signed out without a refresh loop.
- Confirm private responses use
Cache-Control: privateorno-storeat every shared cache.
Production notes
- The SDK cookie codec emits
Path=/; HttpOnly; Secure; SameSite=Laxand uses the__Host-prefix. - Single-flight refresh is per process or isolate. Proactive refresh reduces cross-instance races but cannot eliminate them.
- Refresh tokens rotate on use. Presenting the same refresh token again within 30 seconds returns the same rotated pair, so concurrent refreshes from separate instances converge; after that it returns 401. Retry a protected request at most once after rotation.
- Never serialize a refresh token into HTML, client props, logs, or analytics.
Continue with Caching to keep authenticated responses out of shared caches.