Skip to content

Email verification: code alongside the link, app chooses what to show#51

Open
sambhav-aggarwal wants to merge 1 commit into
mainfrom
feature/email_verification_otp
Open

Email verification: code alongside the link, app chooses what to show#51
sambhav-aggarwal wants to merge 1 commit into
mainfrom
feature/email_verification_otp

Conversation

@sambhav-aggarwal

Copy link
Copy Markdown
Member

What

Implements the dual-proof verification design discussed with the maintainer: the verification email now carries both a signed link and a numeric code, so the session that is waiting can complete verification in place — cross-device signups (register on desktop, read mail on phone), limited-input devices, and environments where corporate security scanners (Outlook SafeLinks, Mimecast) consume single-use links before the user clicks.

The choice mechanism — deliberately not a config toggle

The old email_verification_method key does not return. The package always provides both capabilities; the developer chooses what to surface in code they already own (per RFC 002's template-ownership model):

  • the ejected email-verify template gains $otp in its variable contract (null for reset/email-change purposes) — show the link, the code, or both
  • their frontend decides whether to render a code input

The default template and Blade-kit verification page show both, so the golden path covers every device type with zero decisions.

Mechanics

Piece Detail
Generation AuthService::sendEmailVerification() issues the code with the link — repurposing the previously unused polymorphic otp table (one active code per user; resend replaces it and resets attempts)
Verification POST {prefix}/email/verify-otp (authenticated, throttle 5/min) + a Verify form on the kit's verification page
Security hashed at rest; otp_expiry_time lifetime; hard cap of 5 wrong attempts (OTP::MAX_ATTEMPTS — an invariant, not config); mutual invalidation: whichever proof succeeds kills the other via markEmailAsVerified()
Dedup the API resend endpoint now delegates to the service — which also fixes it ignoring the blade-vs-headless URL choice
Schema otp table gains attempts (edit-in-place migration; UPGRADING note for existing installs)
Docs RFC 002 §5.5 contract updated; api-reference endpoint; SPA guide gains the "verify your email" waiting-screen section (code entry recommended; poll / "I've verified" re-check pattern for link users)

Testing

9 new tests: email carries both proofs, valid/wrong/expired codes, attempt-cap exhaustion kills even the correct code, resend resets attempts and invalidates the old code, link-verification kills the outstanding code, already-verified 400, and reset mails carry no code. Suite 1014 green; Pint and PHPStan clean.

The verification email now carries both proofs — the signed link and a
numeric code — so the session that is WAITING can complete verification
in place: cross-device signups (register on desktop, read mail on
phone), limited-input devices, and environments where security
scanners consume single-use links (Outlook SafeLinks et al).

Which proofs to surface is the developer's choice, exercised in code
they already own — the ejected email-verify template (new $otp
variable in the RFC 002 §5.5 contract) and their UI — not a config
toggle. The old email_verification_method key does not return; the
package always provides both capabilities:

- AuthService::sendEmailVerification() issues the code with the link
  (repurposing the previously unused polymorphic otp table)
- POST {prefix}/email/verify-otp (API, throttle 5/min) and a Verify
  form on the Blade kit's verification page complete it
- Codes: hashed at rest, otp_expiry_time lifetime, invalidated after
  5 wrong attempts (OTP::MAX_ATTEMPTS invariant) and by the link
  succeeding — either proof kills the other via markEmailAsVerified()
- Reset / email-change mails carry no code (link-only purposes)
- API resend endpoint deduplicated through the service (also fixes it
  ignoring the blade-vs-headless URL choice)
- otp table gains an attempts column (UPGRADING note for existing
  installs); SPA guide gains the waiting-screen section (code entry
  or poll/re-check)

9 new tests incl. attempt-cap exhaustion, expiry, resend-resets-
attempts, mutual invalidation, and no-code-on-reset. Suite 1014 green;
Pint and PHPStan clean.
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@codecov-commenter

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 76.56250% with 15 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/Http/Controllers/Auth/UserAuthController.php 0.00% 12 Missing ⚠️
...rc/Http/Controllers/Auth/UserAuthApiController.php 85.71% 3 Missing ⚠️

📢 Thoughts on this report? Let us know!

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.

2 participants