SPEC 001 — Authentication
1. Feature Purpose
Authentication gates every action in the Equa platform. It provides three sign-in methods (password, Google OAuth, magic link), enforces email verification before access, supports optional two-factor authentication, and maintains rolling server-side sessions. Authorization is layered on top via RBAC with per-site read/write permission checks.2. Current State (Verified)
2.1 Password Login
2.2 Google OAuth
2.3 Magic Link
2.4 Sessions
2.5 Authorization (RBAC)
2.6 Auth Form Fields (Frontend)
The login and registration forms usereact-final-form with custom field components that render plain <input type="text">, not <input type="email">. This is intentional — the login field accepts either a username or an email address, so type="email" would reject valid usernames.
Testing implication: E2E selectors must target
input[name="usernameOrEmail"] / input[name="email"], never input[type="email"]. Tests using type="email" selectors silently time out (30s) because the locator never matches. See PR #515 for the full test locator fix.
Source: equa-web/src/modules/auth/pages/login.tsx, equa-web/src/modules/auth/pages/register.tsx, e2e/regression-fixed-issues.spec.ts (PR #515, 2026-04-02).
2.7 Gateway Token Sync (URL Query Params)
The Equa frontend participates in the equabot gateway’s tokenized-URL pattern. When a user lands on the app with?equabotToken=<token> or ?gatewayToken=<token> in the query string, storage.ts reads the token and auto-persists it to localStorage under the gateway-token key.
Why it exists: Before PR #512, a client/server token desync could leave the dashboard unable to reach the gateway even though the user was authenticated. The URL-param handoff lets the gateway hand a fresh token directly to the browser via the landing URL, eliminating the desync class of bug (EQUAStart#502).
Source:
equa-web/src/modules/equabot-settings/services/storage.ts, storage.test.ts (PR #512 Workstream A, 2026-04-01; lint follow-up in PR #513).
3. Data Model
Users
Sessions
TempPasswords
EmailVerifications
Onetimecodes
4. API Endpoints
5. Frontend Components
Frontend Session Handling
- Cookies sent with
credentials: 'include'on every fetch. - 401 responses trigger automatic logout and redirect to login.
- Current user loaded from
GET /api/v1/user/current.
6. Business Rules
- Email verification required — Users cannot access protected routes until
emailVerified = true. - Rolling sessions — Every authenticated request refreshes the session expiry (rolling: true), so active users stay logged in as long as they make a request within every 42-minute window.
- Anti-enumeration on magic links —
sendMagicLink()always returns success, even for unknown emails, to prevent email harvesting. - Secure cookies — The
secureflag is set automatically when SSL is detected, preventing cookie transmission over plain HTTP. - Google auto-registration — First-time Google OAuth users are created automatically; email is pre-verified from Google’s claim.
- RBAC enforcement —
requirePermissions()middleware runs before every protected endpoint;canWriteSite()andcanReadSite()gate organization-level access. - Password hashing — bcryptjs with 10 salt rounds; raw passwords are never stored or logged.
- Magic link expiry — Tokens expire after 15 minutes;
cleanupExpiredMagicLinks()removes stale rows.
7. Acceptance Criteria
- User can register with email + password and receive a verification email
- User cannot access protected routes until email is verified
- User can log in with verified email + correct password
- User can enable and verify TOTP two-factor authentication
- User can sign in with Google OAuth and is auto-registered on first use
- User can request a magic link and log in via the emailed token
- Magic link tokens expire after 15 minutes
- Session persists for up to 42 minutes with rolling refresh
- 401 response on frontend triggers automatic logout
- RBAC guards block unauthorized access to organization resources
- Anti-enumeration: magic link request returns success for non-existent emails