Skip to content

LOGIN-CODE: emailed type-in one-time code (passwordless alternative to the link)#118

Merged
mvalancy merged 1 commit into
devfrom
feat/login-code
Jun 18, 2026
Merged

LOGIN-CODE: emailed type-in one-time code (passwordless alternative to the link)#118
mvalancy merged 1 commit into
devfrom
feat/login-code

Conversation

@mvalancy

Copy link
Copy Markdown
Member

Adds an emailed type-in one-time code as a passwordless alternative to clicking the magic link, so a user can sign in on a device (e.g. a shared/kiosk computer) without opening their email there: read the code on their phone, type it in.

Format: 12 characters shown as XXXX-XXXX-XXXX, from an unambiguous uppercase alphabet — no letter O, no digit 0 (no O/0 confusion). Users may type lowercase and may omit the dashes; both are normalised before matching.

This PR (Core/SPA):

  • lib/loginCode.ts (+ 9 unit tests): alphabet, normalizeLoginCode, live formatLoginCodeInput, isCompleteLoginCode. Normalisation is byte-identical to the Worker's copy (both hash the normalised form).
  • Signin "check your email" view: a code input (auto-formats as you type, autofocuses, Enter submits) → POST /auth/code/verify → persists the returned session token and reloads. Resets on "try a different email".

Paired Worker change (GraphDone-Cloud): /auth/magic-link/request now also mints + stores (hashed, email-keyed) + emails the code; new /auth/code/verify (single-use, 15-min expiry, 5-attempt cap, rate-limited) creates the user on first sign-in and returns a session token; login_codes migration.

Verify: web typecheck clean · loginCode 9/9 + loginFocus 6/6 · THE GATE 5/5 · login-focus e2e 2/2. The code round-trip is exercised live post-deploy (the dev/Neo4j server has no code endpoint).

🤖 Generated with Claude Code

…ve to the link

Lets a user sign in on a device where they don't want to open their email — read
the 12-char code on their phone, type it on the device. Shown in the "check your
email" view alongside the magic link; one email carries both.

- packages/web/src/lib/loginCode.ts (+ tests, 9/9): unambiguous alphabet (no O/0),
  normalize (uppercase, strip dashes, cap 12), live XXXX-XXXX-XXXX formatter,
  isComplete. Normalization is kept byte-identical to the Worker's copy.
- Signin: code input (auto-formats, autoFocus on the sent view, Enter submits) +
  POST /auth/code/verify → persist session token + reload. Field resets on
  "try a different email".

Pairs with the GraphDone-Cloud Worker change (generate/store/email the code +
/auth/code/verify + login_codes table). Web typecheck clean; THE GATE 5/5;
login-focus e2e 2/2.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@mvalancy mvalancy merged commit 2437224 into dev Jun 18, 2026
@mvalancy mvalancy deleted the feat/login-code branch June 18, 2026 17:03
@github-actions

Copy link
Copy Markdown

🧪 Comprehensive Test Suite

  • Unit suites (Node 18.x & 20.x) — core, web, server, mcp-server: ✅ passed
  • Installer & deploy config: ✅ passed

Full-stack smoke gate runs in the CI workflow.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant