From 14de5a80dc949b08e7ecfedaa8d630bf836a4a71 Mon Sep 17 00:00:00 2001 From: Ephraim Atta-Duncan Date: Thu, 6 Nov 2025 03:49:29 +0000 Subject: [PATCH] fix(email-otp): prevent duplicate verification emails when override is enabled --- .../src/plugins/email-otp/email-otp.test.ts | 42 +++++++++++++++++++ .../src/plugins/email-otp/index.ts | 3 +- 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/packages/better-auth/src/plugins/email-otp/email-otp.test.ts b/packages/better-auth/src/plugins/email-otp/email-otp.test.ts index f232d04042..e8de3be198 100644 --- a/packages/better-auth/src/plugins/email-otp/email-otp.test.ts +++ b/packages/better-auth/src/plugins/email-otp/email-otp.test.ts @@ -1012,4 +1012,46 @@ describe("override default email verification", async () => { ); expect(sendVerificationOTP).toHaveBeenCalled(); }); + + it("should send email only once when override is enabled", async () => { + let callCountForTestEmail = 0; + const sendVerificationOTPFn = vi.fn(async (data, request) => { + if (data.email === "test-no-duplicate@email.com") { + callCountForTestEmail++; + } + }); + + const { client } = await getTestInstance({ + emailAndPassword: { + enabled: true, + }, + emailVerification: { + sendOnSignUp: true, + }, + plugins: [ + emailOTP({ + sendVerificationOTP: sendVerificationOTPFn, + overrideDefaultEmailVerification: true, + sendVerificationOnSignUp: true, // This should be ignored when override is true + }), + ], + }); + + sendVerificationOTPFn.mockClear(); + + await client.signUp.email({ + email: "test-no-duplicate@email.com", + password: "password", + name: "Test User", + }); + + expect(sendVerificationOTPFn).toHaveBeenCalledTimes(1); + expect(sendVerificationOTPFn).toHaveBeenCalledWith( + expect.objectContaining({ + email: "test-no-duplicate@email.com", + type: "email-verification", + }), + expect.any(Object), + ); + }); }); diff --git a/packages/better-auth/src/plugins/email-otp/index.ts b/packages/better-auth/src/plugins/email-otp/index.ts index 6bdfb07cb8..540a6e0ec6 100644 --- a/packages/better-auth/src/plugins/email-otp/index.ts +++ b/packages/better-auth/src/plugins/email-otp/index.ts @@ -1152,7 +1152,8 @@ export const emailOTP = (options: EmailOTPOptions) => { matcher(context) { return !!( context.path?.startsWith("/sign-up") && - opts.sendVerificationOnSignUp + opts.sendVerificationOnSignUp && + !opts.overrideDefaultEmailVerification ); }, handler: createAuthMiddleware(async (ctx) => {