Your backend
Server-rendered apps
How the session bridge lets Laravel, Rails, Django, Spring and other server-rendered apps see the ZevAuth session on page requests.
A ZevAuth session lives in the browser. The SDK keeps it there and sends the access token with the requests it makes. That covers single-page apps and API calls.
A server-rendered page is different. The browser asks for
/dashboard itself, with no Authorization header, so your server
can’t tell who is asking before it renders. The session bridge fixes
that by handing the session to your server in a cookie of your own.
How it works
-
You turn the bridge on in the browser SDK:
ZevAuthUI.init({ publishableKey: 'pk_live_...', sessionBridge: { url: '/zevauth/session' }, });It takes the same option in React (
<ZevAuthProvider sessionBridge=…>), Vue, andcreateZevAuth. -
Whenever the session’s access token changes (sign-in, every refresh, switching organization, sign-out), the SDK posts it to that URL on your server.
-
Your server’s bridge endpoint (one line with any ZevAuth server SDK) verifies the token and stores it in an HttpOnly cookie on your domain.
-
Page requests carry the cookie, and your server reads the session from it the same way it reads an
Authorizationheader.
Why your server never refreshes
ZevAuth rotates refresh tokens on every use, and treats a refresh token used twice as stolen: it ends the session. A server refreshing alongside the browser would race it, and the loser would sign the person out. So the refresh token never crosses the bridge.
When the cookie has expired: the handshake
Access tokens live for minutes, so the token in the cookie is often expired by the time someone opens a page. Your server then answers with a handshake instead of the page:
- The server redirects to a small handshake page on your site, remembering where the person was going.
- The handshake page loads the ZevAuth SDK, which refreshes the session if the browser has one, posts the new token over the bridge, and goes back.
- The original page now renders signed in.
This takes a fraction of a second and the person sees no sign-in screen. It’s safe in two ways:
- No loops. The return trip is marked. If the browser had no session either, the page renders signed out instead of trying again.
- No open redirect. The handshake only returns to a path on your own site.
API calls never get a redirect. They get a 401 with
session_refresh_required; send the SDK’s token in Authorization for
those instead.
The cookies
| Cookie | Holds | Lifetime |
|---|---|---|
__Host-zevauth_session | The access token | Until the token expires (minutes) |
__Host-zevauth_client | 1: “this browser has a session” | 30 days, cleared on sign-out |
Both are HttpOnly, Secure and SameSite=Lax, so scripts on the page
can’t read them and other sites can’t use them.
The second cookie holds no credential. It exists because the session cookie deletes itself when the token expires. Without a second signal, “the session expired” and “nobody ever signed in” would look the same, and the handshake could never be offered.
Subdomains. To share the session across app.example.com and
admin.example.com, set the cookie domain to .example.com in your
server SDK. The cookies are then named __Secure-… and carry Domain=.
List every page origin as allowed.
Local development over plain http://. Turn secure off in your
server SDK, since Safari refuses secure cookies on http://localhost.
The cookies then drop their prefix. Never turn it off in production.
Security
- Login CSRF. Another site could try posting its own valid token to
your bridge, to sign your visitor in as someone else. The bridge refuses
any post without the SDK’s
x-zevauth-bridge: 1header (a plain cross-site form can’t add it), and any post whoseOriginis not one of yours. - Every token is verified before it is stored. A token that fails clears the cookies.
- Revocation. The cookie holds a stateless token. A session revoked elsewhere is still accepted by your server until that token expires, within minutes. Routes that must react at once should check with the API.
- Content Security Policy. The handshake page runs one inline script and
loads
@zevauth/ui. Under a strict policy, serve your own copy of the script and allow it.
Signing out
Signing out with the SDK posts a clear to the bridge, which removes both
cookies. If your server also has its own sign-out route, clear the two
cookies there too, but end the ZevAuth session from the browser with the
SDK’s signOut().
Multiple tabs
Each tab posts the token it holds. The posts are idempotent and the newest wins, so tabs never fight over the cookie.
Updated at, Sunday, November 1, 2026