Skip to content

Quick start

After you’ve verified a user’s identity (via a sign-in method), the request lifecycle is:

import { findUserByCommunicationMethod, createSession, withSession } from '@smplcty/auth';
// 1. Resolve the user (e.g. after an OTP/OIDC verification).
const lookup = await findUserByCommunicationMethod(pool, { channel: 'email', code: 'alice@acme.com' });
// 2. Mint a session — returns the raw opaque token ONCE; only its hash is stored.
const session = await createSession(pool, {
userCommunicationMethodId: lookup.userCommunicationMethodId,
ttl: '30 days',
});
setCookie('session', session.token);
// 3. Every authenticated request: resolve + validate + set identity GUCs + run under RLS.
const widgets = await withSession(pool, { token, roleName: 'user' }, async (client, ctx) => {
// ctx = { userId, activeRole, roles, privileges }
const { rows } = await client.query('SELECT * FROM widgets'); // RLS-scoped
return rows;
});

That’s the whole loop: resolve → session → withSession. The library sets the identity GUCs; your RLS policies read them (via current_user_id() and friends). Role and privilege changes take effect on the next request; sign-off is a revoke.

Next: withSession in depth.