V8 Central — Product & Technical Spec
  1. Docs
  2. Frontend spec (from backend doc)
  3. FE: Auth screens (Phase 2)

#FE: Auth screens (from backend Phase 2)

Frontend spec for every feature of backend Phase 2: Authentication & Security (requirements complete 2026-10-01, not built). V8 requirement Backend endpoint paths are not defined yet, so each screen names the capability it needs. When the backend publishes paths, they're added here (auto-sync). Field rules come from the backend doc. Where the doc doesn't say, the V7 behaviour is used and marked V7 only, or the item is marked Assumption.

i18n namespaces: auth.register.*, auth.verify.*, auth.login.*, auth.oauth.*, auth.forgot.*, auth.reset.*, auth.invite.*, auth.twoFactor.*, auth.ipApproval.*, auth.errors.*. All 8 locales.

#2.1 Register

Route: /:locale/register (query: invite, ref, aff) · Public

FieldRuleSource
Namerequired, max 150V8 requirement required · max V7 only
Emailrequired, valid emailV8 requirement
Passwordrequired, min 8 (max 64 as V7 login)V8 requirement min · V7 only max
Turnstilewidget token, requiredV8 requirement
Referral / affiliate / invitation codeoptional. Pre-filled from the query string, read-only when pre-filledV8 requirement "saved now, used in their own phases"
Onboarding questionsoptional. V7 had company size, industry, management experience, heard about usV8 requirement optional · question list Open question (step 2 or the same form?)

States: idle · submitting (button spinner) · 422 field errors · 429 · success → 2.2 check-inbox screen (the account is inactive). Turnstile expiry → re-render the widget. No auto-login after registering (inactive until verified).

#2.2 Email verification

Routes: /:locale/verify-email (check inbox) · /:locale/verify/:token (result) · Public

  • Check-inbox: shows the address, "Resend" with a 60 s cooldown Assumption (backend rate-limits resends, 2.11), and "Wrong email? Register again".
  • Result: success → "Email verified" + Log in button · expired (> 24 h) → "Link expired" + resend · invalid/used → neutral message + log in.

#2.3 Login

Route: /:locale/login?next= · Public (logged-in users → dashboard)

Result from backendScreen behaviour
Wrong email or passwordOne generic message auth.login.invalid
Unverifiedauth.login.unverified + resend verification
Bannedauth.login.banned. No retry
2FA required→ 2.7 step (no token yet)
IP not whitelisted→ 2.8 notice
SuccessToken (BFF cookies) + user + organizations → organization chosen (last used / main / first; none → create organization) → next or dashboard
429Countdown from Retry-After

Fields: email, password (show/hide toggle). Links: forgot password, register, Google, GitHub. Login history is recorded by the backend. Nothing to do on the frontend.

#2.4 Google / GitHub login

Routes: buttons on login/register · callback landing /:locale/oauth/:provider/callback · Public

  • New email → account created. Existing email → linked automatically. V8 requirement
  • Errors come back to /:locale/login?error=<code>: provider disabled, cancelled, email missing, state invalid → translated message. Codes to be agreed Missing.
  • Buttons show only for providers the backend reports as enabled (keys are managed in the admin panel) → needs a public config endpoint Missing (see Runtime configuration).

#2.5 Forgot / reset password

Routes: /:locale/forgot-password · /:locale/reset-password/:token · Public

  • Forgot: email field → always "If an account exists, we sent a link" (no enumeration) Assumption.
  • Reset: new password + confirm (min 8). Link valid 60 min. Success → "Password changed. All devices were signed out" → login. Expired → back to forgot.

#2.6 Invitation password

Route: /:locale/invitations/:token · Public

  • Shows the organization name + inviter (if the backend returns them Missing), a "set your password" form (+ name if unknown), then login → the invited organization becomes the current one.
  • Invalid/expired token → "This invitation is no longer valid".
  • An existing user who opens the link → log in → accept (depends on D-9).

#2.7 2FA at login

Step inside /:locale/login (not a separate URL, so the pending login state isn't bookmarkable).

MethodUI
Email code6-digit input Assumption length, valid 10 min, resend (cooldown), "N tries left" (max 5 wrong)
Google Authenticator6-digit TOTP input
Backup codetext input

Method switch links under the input. After 5 wrong tries → message + back to login. The token is only stored after 2FA passes.

#2.8 IP whitelist at login

  • Login from an unknown IP → screen "We emailed you a link to approve this IP (valid 24 h). Approve it, then log in again."
  • Approval link route /:locale/ip-approval/:key → approved / expired / invalid result + Log in.

#2.9 Tokens & session

  • Access 15 d / refresh 30 d, stored per FE: Foundation D-1.
  • Central issues the token and the refresh token itself, after all checks pass (password → 2FA → IP whitelist), for email and Google/GitHub login alike. The exact method is decided in the backend's Phase 2 plan. V8 requirement 2026-10-03 — for the frontend this means one login response carries both tokens, and the OAuth callback (2.4) is handled the same way as a password login.
  • Refresh once on 401, then retry the original GET. Never replay a mutation automatically.
  • Session expired → /:locale/login?next=<path> + auth.errors.sessionExpired.

#2.10 Logout

User menu → Log out → BFF revokes the token (backend) → clear cookies + client stores → login. Link not prefetched.

#2.11 Rate limits

Every auth form handles 429 with the wait time and disables submit until then. Resend buttons keep their own cooldown.

#Runtime configuration

Settings managed in the backend admin panel affect the screens: Turnstile site key, which social providers are enabled. The frontend can't hard-code them in env files if admins change them at runtime. Needs a public config endpoint (e.g. turnstile_site_key, oauth_providers: ["google","github"], registration_open) Missing. Until then: Open question.

#Phase 2 items not on these screens

  • Organizations aren't auto-created → after the first login, the create-organization screen (Organizations).
  • Dropped V7 sign-up checks (throwaway email, Gmail dots, device fingerprint): no UI.
  • Migration: existing V7 users log in with the same email/password and keep 2FA, IP whitelist and social logins. No special screen is needed Assumption.
ServerAvatar V8 Central · prepared by central-app-2 (Pair 2 frontend) for Bhavik Jethwa · nothing in this spec is implemented yet · Built 2026-10-03 12:35 UTC