Skip to content

fix(auth): expire login OTP codes after the advertised 10 minutes - #2068

Merged
richiemcilroy merged 1 commit into
mainfrom
otp-code-lifetime
Aug 3, 2026
Merged

fix(auth): expire login OTP codes after the advertised 10 minutes#2068
richiemcilroy merged 1 commit into
mainfrom
otp-code-lifetime

Conversation

@richiemcilroy

@richiemcilroy richiemcilroy commented Aug 3, 2026

Copy link
Copy Markdown
Member

The email provider had no maxAge, so next-auth applied its 24 hour default to login codes. The code is 6 digits (900k values), the verify path has no attempt limiting, proxy.ts excludes /api/auth/* from middleware, and the only throttle is a 30 second client-side cooldown that is bypassed by calling the callback URL directly. A day-long window against that keyspace is a practical brute-force target.

The OTP email already tells users "This code will expire in 10 minutes" and the dev console prints the same, so this makes the implementation match the contract users are already given. No user-visible change, 144x smaller window.

Also derives the dev console message from the constant so the two cannot drift again, and adds a test pinning maxAge, since the failure mode here is silent: remove the line and next-auth quietly returns to 24 hours.

Validated: the new test fails when the maxAge line is removed and passes with it, auth-options suite 3/3, typecheck and Biome clean.

Follow-up worth tracking separately: shortening the window reduces exposure but does not close brute force. The durable fix is an attempt counter in useVerificationToken (works for self-hosted too) or Vercel Firewall rules for the AUTH_OTP_VERIFY and AUTH_OTP_SEND ids that already exist unused in lib/rate-limit.ts.

Greptile Summary

The PR aligns login OTP expiration with the advertised ten-minute lifetime.

  • Adds an explicit ten-minute maxAge to the NextAuth email provider.
  • Derives the development-console expiration message from the shared constant.
  • Adds a unit test preventing regression to NextAuth’s longer default.

Confidence Score: 5/5

The PR appears safe to merge, with the implementation and regression test consistently enforcing the advertised ten-minute OTP lifetime.

The email provider now receives an explicit 600-second maximum age, the development message derives from the same constant, and the focused test pins the provider configuration without introducing a blocking failure.

Important Files Changed

Filename Overview
packages/database/auth/auth-options.ts Configures email verification tokens to expire after ten minutes and reuses that duration in development logging; no actionable issue found.
apps/web/tests/unit/auth-options.test.ts Adds a focused regression test asserting the email provider’s explicit ten-minute maximum age; no actionable issue found.

Reviews (1): Last reviewed commit: "fix(auth): expire login OTP codes after ..." | Re-trigger Greptile

@cursor

cursor Bot commented Aug 3, 2026

Copy link
Copy Markdown

Bugbot is not enabled for your account, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

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