Sessions
Configure session storage, cookies, CSRF protection, and revocation.
KavachOS supports two session strategies: database sessions and stateless (JWT) sessions. Database sessions are the default when you use built-in auth plugins. Stateless sessions are a lighter option for read-heavy workloads where you control token revocation outside KavachOS.
Database sessions
A session record is written to kavach_sessions on every sign-in. Each request validates the session ID from the cookie against this table. Revocation is immediate.
import { createKavach } from '@kavachos/core';
import { emailPassword } from '@kavachos/core/plugins/email-password';
const kavach = await createKavach({
database: { provider: 'postgres', url: process.env.DATABASE_URL! },
secret: process.env.KAVACH_SECRET!,
auth: {
session: {
strategy: 'database', // default
secret: process.env.SESSION_SECRET!,
maxAge: 60 * 60 * 24 * 30, // 30 days in seconds
},
},
plugins: [emailPassword()],
});The SESSION_SECRET is used to sign the session cookie (an HMAC). The actual session data lives in the database, not the cookie. Generate it with openssl rand -base64 32.
Stateless sessions
With strategy: 'jwt', KavachOS signs a compact JWT and stores it in the cookie. No database read on each request: the server verifies the signature locally.
auth: {
session: {
strategy: 'jwt',
secret: process.env.SESSION_SECRET!,
maxAge: 60 * 60 * 24 * 7, // 7 days
},
},The trade-off: revoking a stateless session requires a blocklist. See session revocation below.
Cookie configuration
Prop
Type
auth: {
session: {
strategy: 'database',
secret: process.env.SESSION_SECRET!,
maxAge: 60 * 60 * 24 * 30,
cookie: {
name: 'my_app_session',
sameSite: 'strict',
domain: '.example.com', // shared across app.example.com and api.example.com
},
},
},CSRF protection
KavachOS enables CSRF protection by default for all state-changing requests when sameSite is 'lax' or 'none'. It uses the double-submit cookie pattern: a CSRF token is set as a separate readable cookie and must be echoed in the X-CSRF-Token header.
// Read the CSRF token (set automatically on sign-in)
const csrfToken = getCookie('kavach_csrf');
// Include it in fetch calls
fetch('/api/agents', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRF-Token': csrfToken,
},
body: JSON.stringify({ name: 'my-agent' }),
});To disable CSRF protection (not recommended except in trusted internal services):
auth: {
session: {
csrf: false,
},
},Only disable CSRF protection when all requests come from non-browser clients that cannot be tricked via cross-site requests (server-to-server, CLI tools, etc.).
Session revocation
Revoke a single session
// Revoke by session ID (available from kavach.auth.resolveSession(request))
await kavach.auth.revokeSession(sessionId);Revoke all sessions for a user
Useful after a password change or account compromise:
await kavach.auth.revokeAllSessions(userId);Stateless session revocation
JWT sessions cannot be invalidated by deleting a record. KavachOS maintains a revocation blocklist in the database for this case:
// Works for both database and JWT sessions
await kavach.auth.revokeSession(sessionId);For JWT sessions, revokeSession adds the token's jti claim to kavach_revoked_tokens. Every request checks this table. If you want to minimize database reads, set a short maxAge (1 hour or less) and accept that revocation is eventually consistent within that window.
Auto-refresh
When a session is within 25% of its maxAge, KavachOS automatically issues a new cookie with a fresh expiry on the next request. This keeps active users signed in without re-authentication.
// Opt out of auto-refresh
auth: {
session: {
autoRefresh: false,
},
},You can also refresh manually, for example after a permission change:
const response = new Response(body);
await kavach.auth.refreshSession(request, response);
return response;Reading the current session
// From any request handler
const user = await kavach.auth.resolveUser(request);
if (!user) {
return new Response('Unauthorized', { status: 401 });
}
// Full session record (includes expiry and metadata)
const session = await kavach.auth.resolveSession(request);
console.log(session?.expiresAt);Sessions and agents
Sessions are for human users. Agents authenticate via bearer tokens (kv_...), not cookies. The two systems do not interact directly: a session gives you a user.id, and you use that ID as ownerId when creating or querying agents.
const user = await kavach.auth.resolveUser(request);
if (!user) return new Response('Unauthorized', { status: 401 });
const agents = await kavach.agent.listByOwner(user.id);