Repository Public MIT
1# ADR-0009 — Human authentication in V123Status: accepted for V1, 2026-11-09. Deviation from the brief, which preferred Auth.js with passkeys and OAuth.45## Context67Passkeys and OAuth sign-in need registered OAuth applications, a mail sender for verification and recovery, and product decisions about open registration. None of these were available at build time, and the launch has one human user: the owner.89## Decision1011- Email and password. Passwords are 12–200 characters, hashed with argon2id (19 MiB memory, 2 iterations).12- Sessions are rows in PostgreSQL. The cookie `skills_session` carries a 256-bit random value; the database stores only its keyed HMAC. Lifetime 12 hours.13- Cookie-authenticated writes to the API require a same-origin `Origin` header and a per-session CSRF token in `X-CSRF-Token`.14- Sensitive actions (creating or rotating tokens) require the password to have been entered within the last 15 minutes.15- Login is rate limited per IP and email (8 attempts per 15 minutes). Unknown accounts are verified against a dummy hash so timing does not reveal whether an email exists. Failures are audited.16- Changing the password revokes the user's other sessions.17- Accounts are created by the operator from the server console (`pnpm admin:bootstrap`, `pnpm admin user create`) with a generated initial password that must be changed at first sign-in. Until it is changed, the session cannot use the API.18- Recovery is a console command (`pnpm admin recover`), which also revokes all of the user's sessions.19- The first administrator is bound to the owner by possession of shell access on the server. The email is recorded as verified with the note `operator-attested`; no mail is sent.2021## Planned2223TOTP, passkeys (WebAuthn), OAuth sign-in (the `auth_identities` table is in place), self-service registration with email verification, mailed password reset.2425## Consequences2627- No second factor yet: the owner account is protected by one strong password and by the fact that elevated API tokens are short-lived.28- No open registration: contributors are onboarded by the operator.29- No dependency on an external identity provider.30