feat(email-otp): add resendStrategy option to reuse existing OTP (#8560)

This commit is contained in:
Taesu
2026-03-19 12:20:44 -07:00
committed by Bereket Engida
parent 4f41b62cfb
commit 98c8e4e65c
8 changed files with 411 additions and 95 deletions
+20
View File
@@ -411,6 +411,26 @@ export const auth = betterAuth({
When the maximum attempts are exceeded, the `verifyOTP`, `signIn.emailOtp`, `verifyEmail`, and `resetPassword` methods will return an error with code `TOO_MANY_ATTEMPTS`.
- `resendStrategy`: Controls what happens when a user requests a new OTP while an existing one is still valid. Defaults to `"rotate"`.
- `"rotate"`: Always generates a new OTP (default behavior).
- `"reuse"`: Resends the same OTP and extends its expiry. This prevents multiple valid codes from existing simultaneously when emails are delayed. Only works when the OTP is recoverable (`plain`, `encrypted`, or custom encrypt/decrypt). Falls back to `"rotate"` when the OTP is hashed. If the allowed attempts have been exhausted, a fresh OTP is generated instead of reusing the exhausted one.
```ts title="auth.ts"
import { betterAuth } from "better-auth"
import { emailOTP } from "better-auth/plugins"
export const auth = betterAuth({
plugins: [
emailOTP({
resendStrategy: "reuse", // [!code highlight]
async sendVerificationOTP({ email, otp, type }) {
// send the OTP
},
})
]
})
```
- `storeOTP`: The method used to transform the OTP before it is stored by Better Auth's verification layer, whether `encrypted`, `hashed` or `plain` text. Default is `plain` text.
<Callout>