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.