Initial deliverable of the architecture phase: 16 ADRs (stack, CRDT collaboration, plugin sandbox, import/export, backups, CI/CD), data model, permission model, real-time collaboration and plugin concepts, deployment/operations/security documentation, and the milestone roadmap that the implementation issues are derived from. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
62 lines
2.7 KiB
Markdown
62 lines
2.7 KiB
Markdown
# ADR 0007: Cookie sessions, Argon2id, OIDC-ready identity model
|
|
|
|
- Status: accepted
|
|
- Date: 2026-07-04
|
|
|
|
## Context
|
|
|
|
Kickoff decisions: self-contained user management (username, e-mail,
|
|
password) with mandatory e-mail verification (double opt-in), password
|
|
reset, rate limiting, and the option to disable self-registration per
|
|
instance. SSO is not in the MVP but the design must allow adding OIDC login
|
|
later without schema surgery.
|
|
|
|
## Decision
|
|
|
|
### Authentication
|
|
|
|
- **Server-side sessions** stored in PostgreSQL, referenced by an opaque
|
|
`HttpOnly; Secure; SameSite=Lax` cookie. No JWTs for browser sessions
|
|
(revocability and simplicity win). Sliding expiration, default 30 days.
|
|
- Passwords hashed with **Argon2id** (tuned parameters documented in code).
|
|
- **E-mail flows** (verification, password reset) use single-use, expiring,
|
|
hashed tokens; mail is sent via SMTP (instance-configured, see setup
|
|
wizard) through a mail outbox table with retry.
|
|
- **Rate limiting** on signup, login, password reset, and token endpoints:
|
|
fixed-window counters in PostgreSQL keyed by IP and by account —
|
|
no Redis (ADR 0002).
|
|
- Self-registration can be disabled instance-wide
|
|
(`instance_settings.registration_mode`: `open` | `closed`). The kickoff
|
|
also asked for the option of admin approval as a later hardening step; the
|
|
setting is an enum so `approval_required` can be added without migration
|
|
pain.
|
|
- **Collaboration tokens**: the API issues short-lived (≤ 60 s validity for
|
|
connect) signed JWTs solely for the WebSocket handshake with the collab
|
|
server (ADR 0003). These are the only JWTs in the system.
|
|
|
|
### OIDC readiness (not in MVP)
|
|
|
|
- The identity model separates **account** from **login method**:
|
|
`users` (profile, status) and `user_identities`
|
|
(`provider` = `password` | future `oidc:<issuer>`, `subject`,
|
|
`credential`). Password login is just one identity row.
|
|
- E-mail is unique per user and verified; future OIDC linking matches on
|
|
verified e-mail or explicit account linking.
|
|
|
|
## Consequences
|
|
|
|
- Logout and account deactivation are immediate (session rows deleted).
|
|
- No shared secret sprawl: one signing key for collab tokens, rotated via
|
|
environment configuration.
|
|
- Adding OIDC later means: new identity provider rows, an
|
|
authorization-code flow module, and a login button — no changes to
|
|
sessions, permissions, or user references.
|
|
|
|
## Alternatives considered
|
|
|
|
- **JWT access/refresh tokens in the browser**: harder revocation, XSS
|
|
exposure of tokens, no benefit for a same-origin SPA. Rejected.
|
|
- **Auth libraries/services (Keycloak, Authentik as mandatory)**: heavy
|
|
extra container contradicting easy self-hosting; external IdPs remain
|
|
possible later through the OIDC path.
|