Files
familysync/.planning/milestones/v1.1-phases/19-local-auth-no-oidc-mode/19-DISCUSSION-LOG.md
T
2026-06-18 22:21:38 -04:00

7.0 KiB

Phase 19: Local Auth (No-OIDC Mode) - Discussion Log

Audit trail only. Do not use as input to planning, research, or execution agents. Decisions are captured in CONTEXT.md — this log preserves the alternatives considered.

Date: 2026-06-16 Phase: 19-local-auth-no-oidc-mode Areas discussed: Mode & coexistence, Session issuance, Password hashing & storage, Accounts & OIDC-link, Testing & dev-bypass


Mode & Coexistence

Q1 — How should the app decide between local-auth and OIDC?

Option Description Selected
app_config flag (runtime) auth_mode row in app_config, set by wizard; no restart
Deploy-time env switch AUTH_MODE env read at boot
Both always live Local form + OIDC button always shown

User's choice: Free-text — "Default to local and add the ability to wire OIDC in later if wanted." Notes: Local is the always-available default; OIDC is additive/opt-in.

Q2 — How does the app know OIDC is wired in, and what happens to local login?

Option Description Selected
Auto-detect, local stays live OIDC on when config present; local always available (partial)
Auto-detect, OIDC takes over Local disabled once OIDC present
Explicit app_config toggle Separate auth_mode controlled from admin UI (partial)

User's choice: Free-text — OIDC config is set/stored in a later step, so wire it into the admin UI; give users the choice of which to use at login; no local login UI exists today so it must be built. Notes: Blend — admin-UI-configured OIDC, both methods offered at login, user chooses.


Session Issuance

Q1 — What backs a local login session?

Option Description Selected
Stateless signed JWT cookie userId in signed httpOnly cookie; no DB table ✓ (Claude)
Server-side session table sessions table for true revocation
You decide

User's choice: "You decide" + "do not pigeon-hole the user into Authelia — Bring Your Own Auth and Bring Your Own CalDAV provider." Notes: Claude chose stateless signed JWT cookie. User added the BYO-Auth architectural principle (generic OIDC, not Authelia-locked).

Q2 — How far should the BYO-Auth abstraction go in Phase 19?

Option Description Selected
Local + generic OIDC Two concrete methods, clean seam, no framework
Full pluggable framework Provider registry/plugin (LDAP, magic-link, multi-OIDC)
Local only for now Leave Authelia OIDC as-is, defer generic OIDC

User's choice: Local + generic OIDC (recommended). Notes: Clean internal seam now; full framework deferred.


Password Hashing & Storage

Q1 — Which password hashing approach?

Option Description Selected
scrypt via node:crypto Stdlib, zero-dep, no native build
argon2id (native dep) OWASP top pick, needs native addon
bcrypt (bcryptjs) Pure JS, older KDF

User's choice: scrypt via node:crypto (recommended). Notes: Honors the stack's no-native-dep stance.

Q2 — Where to store username + hash?

Option Description Selected
Separate local_credentials table Mirrors member_credentials; user-agnostic users row ✓ (Claude)
Columns on users Add username + password_hash to users
You decide

User's choice: "You decide." Notes: Claude chose a separate local_credentials table — best fits the BYO-Auth per-user-method seam (one row can hold both a local credential and an OIDC binding).


Q1 — How are local accounts created?

Option Description Selected
Admin creates members Wizard creates first admin; admin creates rest
Admin creates + invite link One-time set-password link
Open self-signup Anyone can register

User's choice: Admin creates members.

Q2 — Password change/reset?

Option Description Selected
Self-change + admin reset Member self-change; admin resets lockouts
Self-change only No admin reset
Admin reset only No self-change

User's choice: Self-change + admin reset. Notes: No email reset (email out of scope).

Option Description Selected
Both stay valid Row holds local + OIDC; either logs in
OIDC primary, local fallback Same data model, UI emphasis on OIDC
OIDC replaces local Linking removes local credential ✓ (per user)

User's choice: Initially requested clarification; then chose OIDC replaces local per user — there can/should be OIDC-only users with no local creds. Raised the need for a break-glass path. Notes: Auth methods are per-user (presence of local_credentials row and/or OIDC binding). Break-glass need surfaced here.

Q4 — Break-glass capability model?

Option Description Selected
Protected local admin (no new role model) Initial admin, un-removable local cred
Operator-only account (member/operator split) Strip member capability from break-glass
Let researcher scope it Lock the requirement, defer the how ✓ (twist)

User's choice: Let researcher scope it — with a twist: break-glass can be a CLI/console command or env override instead of a user, removing the added-user/capability complexity. Notes: No new role/capability model; reuse is_admin. Recovery mechanism (not account) to be scoped by researcher.


Testing & Dev-Bypass (added mid-discussion at user's request)

Q1 — How should DEV_AUTH_BYPASS evolve?

Option Description Selected
Bypass stays + seed a real test login Fast bypass for most specs; real form for login specs
Replace bypass with seeded auto-login Harness logs in via real local flow (user's lean)
Bypass auto-issues a real local session Bypass logs in seeded user, skips form

User's choice: Defer final determination to the research agent; user leans toward "replace bypass with seeded auto-login." Notes: Hard constraint — the seeded test login / dev-bypass stays dev-only and never ships in the Docker/prod image (Phase 16 IMG-01/02/03 gates apply).


Claude's Discretion

  • Local session backing → stateless signed JWT cookie (D-05).
  • Credential storage location → separate local_credentials table (D-09).

Deferred Ideas

  • Full pluggable auth-provider framework (registry/plugin; LDAP, magic-link, multi-OIDC) — future phase, counterpart of 999.1.
  • Member-vs-operator capability/role split — rejected in favor of CLI/env break-glass recovery.
  • Email-based password reset — out of project scope.