ZevAuth
Sign up

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

  1. 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, and createZevAuth.

  2. 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.

  3. 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.

  4. Page requests carry the cookie, and your server reads the session from it the same way it reads an Authorization header.

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.

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:

  1. The server redirects to a small handshake page on your site, remembering where the person was going.
  2. 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.
  3. 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

CookieHoldsLifetime
__Host-zevauth_sessionThe access tokenUntil the token expires (minutes)
__Host-zevauth_client1: “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: 1 header (a plain cross-site form can’t add it), and any post whose Origin is 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