feat: email sign-in (one-time code + magic link via Cloudflare Email) - #24
Open
JustWallage wants to merge 4 commits into
Open
feat: email sign-in (one-time code + magic link via Cloudflare Email)#24JustWallage wants to merge 4 commits into
JustWallage wants to merge 4 commits into
Conversation
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds passwordless email sign-in alongside Google: POST /auth/email/request mints a Turnstile-gated 6-digit code (stored only as a salted hash, 10-min TTL, 5-attempt cap, 60s resend cooldown) and emails it through the Cloudflare Email Sending binding; POST /auth/email/verify checks it and mints the same session cookie as the Google callback. The email also carries a magic link that the SPA reads to autofill the code and sign in immediately. - db: email_login_codes table + migration 0006 - worker/lib/email-login.ts: OTP issue/verify/purge (fake-seam-free, pure D1) - worker/lib/email.ts: EmailSender seam (real binding in prod, no-op fake in local/e2e; fail-closed 503 when unconfigured) - shared/api.ts: request/verify/result schemas - LandingPage.tsx: two-step email form + magic-link autofill, shared Turnstile - maintenance: purge expired codes nightly - devCode returned only in local/e2e (prod-absent invariant) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What & why
Lets new users create an account with any email address, not just a Google account. Identity in this app is already email-only (no users table —
createSession(email)works for any email), so a verified email is the account. This is purely additive: the Google button is unchanged.On the "via Google IdP?" question: Google's IdP only authenticates Google accounts — it can't verify ownership of an arbitrary email — so an independent email-verification flow is required alongside it.
How it works
POST /auth/email/request— Turnstile-gated; mints a 6-digit one-time code, stores it as a salted hash (sha256Hex(email:code)), and emails it via the Cloudflare Email Sending binding. The email also carries a magic link (/?login_email=…&login_code=…).POST /auth/email/verify— checks the code and mints the same session cookie as the Google callback.Decisions
send_emailbinding, no third-party key).EMAIL_FROM/binding absent), mirroringmakeGoogleAuth.devCodereturned in the request response only in local/e2e (prod-absent invariant).Operational prerequisite
Before this works in production, Cloudflare Email Sending must be enabled for the
EMAIL_FROMdomain (wrangler email sending enable <domain>+ SPF/DKIM/DMARC).Verification
pnpm checkgreen (118 unit tests).pnpm test:e2egreen (24 tests, incl. 3 new email-signin specs).docs/specs/email-signin/.🤖 Generated with Claude Code