feat(auth): split auth — magic-link for customers, email+password for support agents (v0.3.0) #4

Closed
opened 2026-05-01 02:14:55 +00:00 by mik-tf · 1 comment
Owner

Why

Industry-standard ticketing tools (Zendesk, Intercom, Help Scout, Linear customer portal) all split auth by role:

Role Pattern Why
Customer Magic-link / email-on-thread Transient relationship; one ticket per quarter; account-creation friction kills filing
Support agent Email + password (+ 2FA / SSO) Employee; daily login; password manager; account compromise = much higher impact
Admin Same as agent + extra MFA Highest impact

v0.2.0 ships with magic-link for everyone (current Phase 3 / D-04 / D-06 design). It's correct and secure but creates a daily-email papercut for support agents that compounds. v0.3.0 closes that gap.

Sequencing — depends on #5 (Phase 18)

This is Phase 20 in the roadmap, gated by #5 (Phase 18) for the security-row spec matrix. Reason: auth is the highest-stakes feature; the freezone-pattern checklist gives us a "Section AU: auth" row matrix where every claim ("password rotated revokes session" / "rate-limit kicks in after 5 fails" / "magic-link single-use") has a Schema/Wired/MCP/Browser/Human row. B.5 adversarial review must run on the design before any code lands.

Deliverables

  1. Server: new user_credentials table; argon2id hashing; new RPCs auth.login / auth.create_password (admin-only) / auth.change_password / auth.reset_password_request / auth.reset_password_consume; session-cookie management (sliding window, HttpOnly/Secure/SameSite=Strict); login-failure rate-limiting (per-email + per-IP).
  2. _ui_wasm: new /login route with email+password form (separate from /enroll); role-aware sign-in CTA — "Customer? Get a sign-in link." vs "Support agent? Log in."; password-reset flow.
  3. Admin UI: "Create support agent" form (email + role + initial password OR send-setup-email); "Reset password" admin action.
  4. Migration: users with role: "agent" or "admin" get a "set your password" prompt on next sign-in. Customers stay on magic-link untouched.
  5. Decision files:
    • D-XX-auth-split.md — dual-path architecture
    • D-XX-password-storage.md — argon2id parameters, salt strategy, work factor
  6. Security review — OWASP top-10 for auth: credential stuffing, account enumeration via timing, session fixation, CSRF on cookie-based RPC, password-compare timing attack.

Out of scope (later releases)

  • SSO (SAML / OIDC) — v0.4.0+ for enterprise
  • 2FA / TOTP — v0.4.0
  • Federated identity across projects — D-04 says identities are per-project; cross-project is an explicit non-goal

Risk markers

  • Password storage = compliance scope (GDPR; possibly SOC 2 if going enterprise)
  • New attack surface — Phase B.5 adversarial review must run on the design before any code lands
  • D-04 invariants must hold — adding password auth doesn't change identity layering, just adds a credential type to the user layer

Dependencies

  • #5 (Phase 18) — security-row spec matrix
  • #3 (Phase 19) — Playwright specs that exercise both auth paths and assert on session-cookie behavior

Estimated effort

3-4 sessions

## Why Industry-standard ticketing tools (Zendesk, Intercom, Help Scout, Linear customer portal) all split auth by role: | Role | Pattern | Why | |---|---|---| | Customer | Magic-link / email-on-thread | Transient relationship; one ticket per quarter; account-creation friction kills filing | | Support agent | Email + password (+ 2FA / SSO) | Employee; daily login; password manager; account compromise = much higher impact | | Admin | Same as agent + extra MFA | Highest impact | v0.2.0 ships with magic-link for everyone (current Phase 3 / D-04 / D-06 design). It's correct and secure but creates a daily-email papercut for support agents that compounds. v0.3.0 closes that gap. ## Sequencing — depends on #5 (Phase 18) This is **Phase 20** in the roadmap, gated by #5 (Phase 18) for the security-row spec matrix. Reason: auth is the highest-stakes feature; the freezone-pattern checklist gives us a "Section AU: auth" row matrix where every claim ("password rotated revokes session" / "rate-limit kicks in after 5 fails" / "magic-link single-use") has a Schema/Wired/MCP/Browser/Human row. B.5 adversarial review must run on the design before any code lands. ## Deliverables 1. **Server:** new `user_credentials` table; argon2id hashing; new RPCs `auth.login` / `auth.create_password` (admin-only) / `auth.change_password` / `auth.reset_password_request` / `auth.reset_password_consume`; session-cookie management (sliding window, `HttpOnly`/`Secure`/`SameSite=Strict`); login-failure rate-limiting (per-email + per-IP). 2. **`_ui_wasm`:** new `/login` route with email+password form (separate from `/enroll`); role-aware sign-in CTA — "Customer? Get a sign-in link." vs "Support agent? Log in."; password-reset flow. 3. **Admin UI:** "Create support agent" form (email + role + initial password OR send-setup-email); "Reset password" admin action. 4. **Migration:** users with `role: "agent"` or `"admin"` get a "set your password" prompt on next sign-in. Customers stay on magic-link untouched. 5. **Decision files:** - `D-XX-auth-split.md` — dual-path architecture - `D-XX-password-storage.md` — argon2id parameters, salt strategy, work factor 6. **Security review** — OWASP top-10 for auth: credential stuffing, account enumeration via timing, session fixation, CSRF on cookie-based RPC, password-compare timing attack. ## Out of scope (later releases) - SSO (SAML / OIDC) — v0.4.0+ for enterprise - 2FA / TOTP — v0.4.0 - Federated identity across projects — D-04 says identities are per-project; cross-project is an explicit non-goal ## Risk markers - Password storage = compliance scope (GDPR; possibly SOC 2 if going enterprise) - New attack surface — Phase B.5 adversarial review **must** run on the design before any code lands - D-04 invariants must hold — adding password auth doesn't change identity layering, just adds a credential type to the user layer ## Dependencies - #5 (Phase 18) — security-row spec matrix - #3 (Phase 19) — Playwright specs that exercise both auth paths and assert on session-cookie behavior ## Estimated effort 3-4 sessions
Author
Owner

Closing this as wrong scope for hero_assistance after a re-evaluation in session 24.

The original framing ("industry-standard ticketing tools split auth by role") was an unexamined SaaS-pattern import. hero_assistance isn't a SaaS — it's a Hero-stack component:

  • D-04/D-05 already provide cryptographically strong device-level auth via mycelium overlay addresses (kernel-validated 400::/7). That's mTLS-equivalent without cert management.
  • D-09 §"Argument" pt 5 makes embed-as-Support-tab the primary deployment. When hero_assistance lives inside Hero OS / freezone admin / TFGrid console, the host shell's auth is the auth. A separate hero_assistance password is duplicate state and bad UX.
  • The "daily-email papercut" cited in the original body only matters if support agents use the standalone SPA daily. In the embed-as-Support-tab model they never see hero_assistance's login.
  • Password storage drags in compliance scope (GDPR, possibly SOC 2) for limited benefit.

The honest v0.3.0+ auth answers, when a real customer deployment surfaces a real gap, are:

  • Remember-me cookie (30-day signed JWT keyed on device_addr) — one-session feature when the daily papercut becomes real
  • Host-JWT delegation when embedded — Authorization: Bearer <host-jwt> validated against configurable JWKS; no magic-link in the embed path
  • OIDC for standalone SPAs that customers want SSO on (Okta / Google Workspace / Microsoft Entra) — well-trodden libraries, no password storage

None of these are needed for v0.2.0 or v0.3.0 in the abstract. They get filed as precise issues when a real customer deployment requires them. Per the project's "anchor on stated specs" guideline (feedback_scope_discipline.md), we don't pre-build auth subsystems for imagined requirements.

Magic-link-for-everyone (current behaviour) is the answer indefinitely. No "auth split" phase. The roadmap reduces to Phase 18 (spec docs, #5) + Phase 16b (visual polish, #2) + Phase 19 (E2E test suite, #3) for v0.2.0 → v1.0.

Refs: D-04, D-05, D-09, decisions/D-18-spec-as-checklist.md (Section J of the e2e_checklist will document the three candidate v0.3.0+ paths so the discussion is preserved without committing to an implementation).

Closing this as **wrong scope for hero_assistance** after a re-evaluation in session 24. The original framing ("industry-standard ticketing tools split auth by role") was an unexamined SaaS-pattern import. hero_assistance isn't a SaaS — it's a Hero-stack component: - **D-04/D-05** already provide cryptographically strong device-level auth via mycelium overlay addresses (kernel-validated `400::/7`). That's mTLS-equivalent without cert management. - **D-09 §"Argument" pt 5** makes embed-as-Support-tab the *primary* deployment. When hero_assistance lives inside Hero OS / freezone admin / TFGrid console, **the host shell's auth is the auth**. A separate hero_assistance password is duplicate state and bad UX. - **The "daily-email papercut" cited in the original body** only matters if support agents use the *standalone* SPA daily. In the embed-as-Support-tab model they never see hero_assistance's login. - **Password storage drags in compliance scope** (GDPR, possibly SOC 2) for limited benefit. The honest v0.3.0+ auth answers, when a real customer deployment surfaces a real gap, are: - **Remember-me cookie** (30-day signed JWT keyed on `device_addr`) — one-session feature when the daily papercut becomes real - **Host-JWT delegation** when embedded — `Authorization: Bearer <host-jwt>` validated against configurable JWKS; no magic-link in the embed path - **OIDC** for standalone SPAs that customers want SSO on (Okta / Google Workspace / Microsoft Entra) — well-trodden libraries, no password storage None of these are needed for v0.2.0 or v0.3.0 in the abstract. They get filed as precise issues when a real customer deployment requires them. Per the project's "anchor on stated specs" guideline (`feedback_scope_discipline.md`), we don't pre-build auth subsystems for imagined requirements. **Magic-link-for-everyone (current behaviour) is the answer indefinitely.** No "auth split" phase. The roadmap reduces to Phase 18 (spec docs, #5) + Phase 16b (visual polish, #2) + Phase 19 (E2E test suite, #3) for v0.2.0 → v1.0. Refs: D-04, D-05, D-09, decisions/D-18-spec-as-checklist.md (Section J of the e2e_checklist will document the three candidate v0.3.0+ paths so the discussion is preserved without committing to an implementation).
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
lhumina_code/hero_assistance#4
No description provided.