
Credentials done right
argon2id via @node-rs/argon2 with an injected pepper. The hash in your database is useless without the app secret.
Signup, login, email verification and password reset as a library — argon2id with an app-held pepper, server-side revocable sessions, enumeration-safe flows. It produces the opaque UserId the rest of the family consumes. MFA, API keys and Sign in with Google/Apple ship opt-in, not as defaults. This portal runs on it.


argon2id via @node-rs/argon2 with an injected pepper. The hash in your database is useless without the app secret.

Sessions are server-side and opaque, so a logout actually ends the session — not a token you hope expires.

Signup, login and reset return the same shape whether or not the account exists. The flow does not leak who is a member.

The id the rest of the family keys on, in its own schema namespace, over the same SqlExecutor seam.

TOTP via otpauth, the secret sealed with AES-256-GCM. Opt-in per account, never forced on everyone.

OIDC via openid-client with an explicit account-linking policy — Google and Apple as entry points, not a security hole.
Password, a sealed TOTP, a scoped API key — layered, each opt-in.
Check the credential — password against an argon2id hash, or an OIDC assertion — enumeration-safe throughout.
Mint a server-side session bound to the opaque UserId. Optionally step up with MFA.
End any session on demand. Because sessions live in your database, revocation is immediate and real.
import { signup, login, sessions } from 'identity-kit';
// argon2id with an app-held pepper; enumeration-safe by construction
const user = await signup(sql, { email, password, pepper });
// server-side and revocable — a logout actually ends the session
const session = await login(sql, { email, password, pepper });
await sessions.revoke(sql, session.id);A session you cannot revoke is a promise you cannot keep. Keep sessions where you can end them.