Browse docs

Sessions & refresh

KolayLogin ships a two-cookie session model. A short-lived JWT handles authorization; a long-lived rotating cookie refreshes it without exposing the user to replay or hijack.

Copy this quickstart guide as a prompt for LLMs to implement KolayLogin in your application.

Cookies

  • __client: HttpOnly, Secure (prod), SameSite=lax. Value is clientId.rotatingToken. Plan-aware max age: Hobby 7 days, Pro 30 days, Business / Enterprise 365 days. Rotated on every refresh. JS cannot read it.
  • __session: JS-readable, Secure (prod), SameSite=None (prod) / lax (dev). 60-second RS256 JWT signed with the app's RSA keypair, verifiable via public /.well-known/jwks.json.

JWT claims

{
  "sid": "session-uuid",
  "sub": "user-uuid",
  "env": "environment-uuid",
  "org": "active-org-uuid",
  "org_role": "admin",
  "iss": "https://api.kolaylogin.com",
  "iat": 1761940000,
  "exp": 1761940060
}

Refresh

When __session is near its exp, the client POSTs /v1/auth/sessions/refresh. The API reads__client, verifies the rotating token, writes a new one, and mints a fresh __session JWT. If the rotating token ever shows up twice (browser replay, stolen cookie), we revoke the whole client.

// The React provider does this automatically:
const res = await fetch(base + '/v1/auth/sessions/refresh', {
  method: 'POST',
  credentials: 'include',
});

Sign out

  • POST /v1/auth/sign-out — end this browser. Clears cookies, marks the session ended, rotates the stored token so the cookie (if stolen) is dead.
  • POST /v1/auth/sign-out/all — end every session for the signed-in user. Use after a password reset or compromised-device alert.

Verifying a session on your own API

import { verifySessionJwt } from '@kolaylogin/backend';

app.use(async (req, res, next) => {
  const jwt = getCookie(req, '__session');
  if (!jwt) return res.status(401).end();
  try {
    req.auth = await verifySessionJwt(jwt, {
      jwksUrl: "https://api.kolaylogin.com" + '/.well-known/jwks.json',
      issuer: process.env.KL_JWT_ISSUER,
    });
  } catch {
    return res.status(401).end();
  }
  next();
});
Why 60 seconds for the JWT?
Short TTLs limit damage from cookie theft. The __client cookie carries the long-lived trust; the JWT is a transient proof of that trust. If your API caches auth state on a gateway, stale-JWT latency is bounded to 60s — reverse proxies can keep their JWKS cache indefinitely.

Plan caps

The __client cookie's max age is clamped by the workspace plan's maxSessionTtlSeconds. A dashboard admin cannot raise it above the plan limit.

  • Hobby — 7 days
  • Pro — 30 days
  • Business / Enterprise — 365 days