Apache-2.0 · accounts & sessions

Accounts and sessions, honest by default

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.

Get started$ npm i @quxkit/identity-kit
Apache-2.0
identity-kit crystal
argon2id
password hashing with an app-held pepper the database never sees
0
plaintext secrets at rest — TOTP seeds are AES-256-GCM sealed
0
opt-in entry points: MFA, API keys, Sign in with Google/Apple
1
opaque UserId the whole family consumes, over one SqlExecutor
What it is

One library, whole — not a platform you rent

Credentials done right

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

Revocable sessions

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

Enumeration-safe

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

One opaque UserId

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

MFA, sealed

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

Social sign-in

OIDC via openid-client with an explicit account-linking policy — Google and Apple as entry points, not a security hole.

By the shape of it

A session you cannot revoke is a promise you cannot keep. Keep sessions where you can end them.

3 factors
45% Password
30% MFA
25% API key

Password, a sealed TOTP, a scoped API key — layered, each opt-in.

How it works

Three moves, in order

01
Verify

Check the credential — password against an argon2id hash, or an OIDC assertion — enumeration-safe throughout.

02
Issue

Mint a server-side session bound to the opaque UserId. Optionally step up with MFA.

03
Revoke

End any session on demand. Because sessions live in your database, revocation is immediate and real.

identity-kit.ts
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.

identity-kit

Embed it in the app you already run