apistockdocs
Decisions

Authentication methods

ADR-0024Accepted

Status: Accepted (2026-09-14) · Supersedes: ADR-0006 · Amended by: ADR-0038 (flows, tables and SQL live in the generated app's internal/modules/auth; modules/auth provides building blocks), ADR-0043 (2FA details; TOTP implemented in modules/auth instead of pquerna/otp), ADR-0044 (passkeys: sign-in and second factor, configuration in env, native association files), ADR-0046 (Google and Apple: API-hosted web flow, native ID tokens with server nonces, automatic linking that removes an unverified account's password, second factor still required)

Context#

The Full preset promises complete authentication on first run. Authentication is the highest-risk area: it must be secure by default, support web and native mobile clients, and receive security fixes through the library rather than copied code.

Options#

  1. JWT access + refresh tokens, social login through a vendor SDK (for example Firebase).
  2. External identity service (Ory, Keycloak, Auth0) required for every app.
  3. Embedded library with server-side sessions and standards-based social login, 2FA and passkeys; owned HTTP handlers in the app.

Decision#

Option 3. Logic lives in apistock.dev/modules/auth; the generated internal/modules/auth holds endpoints, customisable rules and adapters.

Methods and flows (Full preset)#

CapabilityDesignMilestone
Email + passwordargon2id with stored parameters, rehash on login; minimum length 12; optional breached-password check hookv0.2
Email verification6-digit code, hashed, 15-minute expiry, attempt-limited, resend throttledv0.2
SessionsOpaque 32-byte token; only SHA-256 stored; __Host- cookie (Secure, HttpOnly, SameSite=Lax) for browsers or Authorization: Bearer for native clients; idle and absolute expiry; rotation on login and privilege changev0.2
Logout / logout allRevoke one or all sessionsv0.2
Password resetSingle-use hashed code or token, 30-minute expiry, identical response whether or not the email exists, all sessions revoked on successv0.2
Change passwordRequires the current password; other sessions revokedv0.2
Active sessionsList devices; revoke onev0.2
Delete accountSoft delete, sessions revoked, purge job after retention periodv0.2
Platform roles and permission catalogModules declare permissions; roles are sets of permissions; deny by defaultv0.2
Google sign-inOIDC authorization code + PKCE with state and nonce (web); ID-token verification (native)v0.3
Apple sign-inSame two flows; client secret signed per request from the .p8 key; name stored on first sign-in; private relay emails supportedv0.3
Account linkingOnly on a verified email matchv0.3
TOTP 2FASecret encrypted at rest with a rotatable app key; 10 hashed recovery codes; codes rate-limited and single-use; mfa_required challenge before a session is createdv0.3
PasskeysWebAuthn registration and login; relying-party ID and allowed origins configured; counts as strong 2FA; apple-app-site-association and assetlinks.json servedv0.3
2FA policyRoles can require 2FA; ops roles require itv0.3
GitHub login, API keysCustom option / v1.1v1.1
SAML, SCIM, enterprise SSODelegated to identity providersLater

Social providers are included but disabled until credentials are configured; aps dev reports their status.

Security rules#

  • No account enumeration on register, login or reset responses.
  • CSRF protection for cookie-authenticated routes (http.CrossOriginProtection).
  • Per-account and per-IP rate limits; no hard lockout.
  • Security events recorded through audit.Recorder (login succeeded/failed, MFA enrolled, passkey added, password changed, session revoked).
  • A new sign-in alert email for unrecognised devices.

Libraries#

golang.org/x/crypto/argon2, golang.org/x/oauth2, github.com/coreos/go-oidc, github.com/pquerna/otp, github.com/go-webauthn/webauthn.

Why#

  • Revocable sessions are simpler and safer than JWT session tokens.
  • Standards-based providers avoid vendor SDK lock-in.
  • Security fixes ship through go get.

Trade-offs#

  • A large security surface to maintain; an external security review is required before 1.0.
  • Apple web sign-in can't use localhost redirects; local testing uses the native flow or a tunnel (documented).

Consequences#

  • The data model for MFA challenges and role scopes is designed in v0.2 even though the features ship in v0.3–v0.4.
  • docs/auth-providers.md in generated apps explains Google, Apple and passkey setup.
esc
↑↓ move↵ openesc close