feat(auth): Add email verification to user registration to verify email ownership. - #7978
feat(auth): Add email verification to user registration to verify email ownership.#7978Neilk1021 wants to merge 4 commits into
Conversation
Automated Reviewer SuggestionsBased on the
|
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #7978 +/- ##
============================================
- Coverage 92.86% 92.82% -0.04%
- Complexity 4631 4659 +28
============================================
Files 1174 1176 +2
Lines 47442 47612 +170
Branches 5304 5334 +30
============================================
+ Hits 44056 44196 +140
- Misses 1877 1890 +13
- Partials 1509 1526 +17
*This pull request uses carry forward flags. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
|
| config | throughput | MB/s | latency | max Δ latest / 7d | |
|---|---|---|---|---|---|
| 🔴 | bs=10 sw=10 sl=64 | 441 | 0.269 | 21,821/27,042/27,042 us | 🔴 -7.6% / 🔴 +100.1% |
| 🟢 | bs=100 sw=10 sl=64 | 939 | 0.573 | 104,946/120,335/120,335 us | 🟢 -9.3% / 🔴 +31.4% |
| 🟢 | bs=1000 sw=10 sl=64 | 1,088 | 0.664 | 916,357/952,788/952,788 us | 🟢 -9.1% / 🔴 -10.9% |
Baseline details
Latest main 0af18e0 from same runner
| config | metric | PR | latest main | 7d avg | Δ latest | Δ 7d |
|---|---|---|---|---|---|---|
| bs=10 sw=10 sl=64 | throughput | 441 tuples/sec | 477 tuples/sec | 908.02 tuples/sec | -7.5% | -51.4% |
| bs=10 sw=10 sl=64 | MB/s | 0.269 MB/s | 0.291 MB/s | 0.554 MB/s | -7.6% | -51.5% |
| bs=10 sw=10 sl=64 | p50 | 21,821 us | 21,439 us | 10,907 us | +1.8% | +100.1% |
| bs=10 sw=10 sl=64 | p95 | 27,042 us | 28,042 us | 13,604 us | -3.6% | +98.8% |
| bs=10 sw=10 sl=64 | p99 | 27,042 us | 28,042 us | 16,697 us | -3.6% | +62.0% |
| bs=100 sw=10 sl=64 | throughput | 939 tuples/sec | 950 tuples/sec | 1,188 tuples/sec | -1.2% | -20.9% |
| bs=100 sw=10 sl=64 | MB/s | 0.573 MB/s | 0.58 MB/s | 0.725 MB/s | -1.2% | -20.9% |
| bs=100 sw=10 sl=64 | p50 | 104,946 us | 100,595 us | 85,003 us | +4.3% | +23.5% |
| bs=100 sw=10 sl=64 | p95 | 120,335 us | 132,654 us | 91,599 us | -9.3% | +31.4% |
| bs=100 sw=10 sl=64 | p99 | 120,335 us | 132,654 us | 99,202 us | -9.3% | +21.3% |
| bs=1000 sw=10 sl=64 | throughput | 1,088 tuples/sec | 1,080 tuples/sec | 1,221 tuples/sec | +0.7% | -10.9% |
| bs=1000 sw=10 sl=64 | MB/s | 0.664 MB/s | 0.659 MB/s | 0.745 MB/s | +0.8% | -10.9% |
| bs=1000 sw=10 sl=64 | p50 | 916,357 us | 919,073 us | 837,593 us | -0.3% | +9.4% |
| bs=1000 sw=10 sl=64 | p95 | 952,788 us | 1,047,729 us | 881,015 us | -9.1% | +8.1% |
| bs=1000 sw=10 sl=64 | p99 | 952,788 us | 1,047,729 us | 915,550 us | -9.1% | +4.1% |
Raw CSV
config_idx,batch_size,schema_width,string_len,num_batches,total_ms,total_tuples,total_bytes,tuples_per_sec,mb_per_sec,lat_p50_us,lat_p95_us,lat_p99_us
0,10,10,64,20,453.49,200,128000,441,0.269,21820.94,27042.29,27042.29
1,100,10,64,20,2129.54,2000,1280000,939,0.573,104946.01,120335.42,120335.42
2,1000,10,64,20,18389.98,20000,12800000,1088,0.664,916357.14,952787.80,952787.80
What changes were proposed in this PR?
An email address a user types is now proved by a code mailed to it before it is accepted at registration, and when a signed-in account with no address on file supplies one. An address a provider already asserts as verified (Google's
email_verified) is trusted and never re-checked.The hole this closes: a dataset contributor placeholder is a real account that contributor rows already point at, and until now anyone could claim it by typing a colleague's address.
Codes are derived, not stored.
EmailCodeVerifiercomputes a 6-digit code as a truncated HMAC (RFC 4226 style) overpurpose | scope | address | time-step, keyed from the JWT secret, and checks it by recomputing for the current and previous step:Consequences of that choice:
email_verificationtableregisterVerifytakes the password againA code is valid 5–10 minutes (one step plus the previous). Resend cooldown, a per-scope
attempt cap, and eviction of stale trackers live in an in-memory map;
/auth/registerisunauthenticated, so that map is bounded deliberately rather than incidentally.
Defaults.
user-sys.email-verificationships on — an unproven address is the weakerposition, so a deployment opts out of checking rather than into it. It must agree with
user-sys.google.smtp.gmail: on with no sender configured is a misconfiguration, not adegraded mode, and both entry points refuse with a 503 naming the two settings rather than
logging the code where anyone with log access could spend it.
bin/local-dev.shsetsUSER_SYS_EMAIL_VERIFICATION=false, since a local stack has no sender; an explicit exportstill wins.
New endpoints:
POST /auth/register/verifyandPOST /auth/email/code.POST /auth/registernow answers with
RegistrationResponse, whose nullaccessTokenis the "a code was mailed"signal — it is not reported separately, so the two cannot drift apart.
Any related issues, documentation, discussions?
Closes #7977
Discussion #7818
How was this PR tested?
Automated, all run on this branch:
EmailCodeVerifierSpecis new (20 cases): code derivation and its independence from anystored state, acceptance across the step boundary, rejection of a code minted for a different
address / scope / purpose / secret, the resend cooldown, the attempt cap, and the refusal when
SMTP is unconfigured.
AuthResourceSpecgains 12 cases covering both endpoint flows with theverification seam pinned on.
Note for anyone running these locally:
AuthResource.emailVerificationRequiredreadsUserSystemConfig, an object val resolved once per JVM. Both suites pin the flag explicitlyrather than inheriting it, so they pass whether or not
USER_SYS_EMAIL_VERIFICATIONisexported in your shell — verified both ways.
Was this PR authored or co-authored using generative AI tooling?
Generated-by: Claude Code (Claude Opus 5)