[GH-ISSUE #8480] signUpEmail doesn't throw error when duplicate email caught #28426

Open
opened 2026-04-17 19:52:49 -05:00 by GiteaMirror · 3 comments
Owner

Originally created by @mdarkanurl on GitHub (Mar 7, 2026).
Original GitHub issue: https://github.com/better-auth/better-auth/issues/8480

Is this suited for github?

  • Yes, this is suited for github

To Reproduce

  1. Create a sign-up function where I use the signUpEmail API.
  2. Previously, the signUpEmail API threw an error when it encountered a duplicate email.
  3. However, with @thallesp/nestjs-better-auth ^2.4.0 and better-auth ^1.4.20, it no longer throws an error for duplicate emails.

Current vs. Expected behavior

Image

I created a sign-up function using the signUpEmail API.
Before, it threw an error if the email already existed.
With @thallesp/nestjs-better-auth ^2.4.0 and better-auth ^1.4.20, it no longer throws that duplicate email error.

What version of Better Auth are you using?

^1.4.20

System info

{
  "system": {
    "platform": "win32",
    "arch": "x64",
    "version": "Windows 11 Pro",
    "release": "10.0.26200",
    "cpuCount": 16,
    "cpuModel": "AMD Ryzen 7 5700G with Radeon Graphics         ",
    "totalMemory": "7.40 GB",
    "freeMemory": "1.00 GB"
  },
  "node": {
    "version": "v22.20.0",
    "env": "development"
  },
  "packageManager": {
    "name": "npm",
    "version": "10.9.3"
  },
  "frameworks": null,
  "databases": [
    {
      "name": "pg",
      "version": "^8.19.0"
    },
    {
      "name": "@prisma/client",
      "version": "^7.4.2"
    }
  ],
  "betterAuth": {
    "version": "^1.4.20",
    "config": {
      "url": "http://localhost:3000",
      "secret": "[REDACTED]",
      "emailAndPassword": {
        "enabled": true,
        "requireEmailVerification": true,
        "resetPasswordTokenExpiresIn": 300,
        "revokeSessionsOnPasswordReset": true
      },
      "emailVerification": {
        "autoSignInAfterVerification": true,
        "sendOnSignUp": true,
        "expiresIn": 300
      },
      "rateLimit": {
        "enabled": true,
        "window": 60,
        "max": 100,
        "customRules": {
          "/sign-in/email": {
            "window": 10,
            "max": 3
          },
          "/sign-up/email": {
            "window": 10,
            "max": 3
          }
        }
      },
      "advanced": {
        "ipAddress": {
          "ipAddressHeaders": [
            "x-forwarded-for",
            "cf-connecting-ip"
          ]
        }
      },
      "trustedOrigins": [
        "http://localhost:3000"
      ]
    }
  }
}

Which area(s) are affected? (Select all that apply)

Backend

Auth config (if applicable)

import { betterAuth } from "better-auth"
export const auth = betterAuth({
  emailAndPassword: {  
    enabled: true
  },
});

Additional context

No response

Originally created by @mdarkanurl on GitHub (Mar 7, 2026). Original GitHub issue: https://github.com/better-auth/better-auth/issues/8480 ### Is this suited for github? - [x] Yes, this is suited for github ### To Reproduce 1. Create a sign-up function where I use the signUpEmail API. 2. Previously, the signUpEmail API threw an error when it encountered a duplicate email. 3. However, with @thallesp/nestjs-better-auth ^2.4.0 and better-auth ^1.4.20, it no longer throws an error for duplicate emails. ### Current vs. Expected behavior <img width="695" height="519" alt="Image" src="https://github.com/user-attachments/assets/3c253cde-3ae6-4f64-89ea-7ab75db289c9" /> I created a sign-up function using the signUpEmail API. Before, it threw an error if the email already existed. With @thallesp/nestjs-better-auth ^2.4.0 and better-auth ^1.4.20, it no longer throws that duplicate email error. ### What version of Better Auth are you using? ^1.4.20 ### System info ```bash { "system": { "platform": "win32", "arch": "x64", "version": "Windows 11 Pro", "release": "10.0.26200", "cpuCount": 16, "cpuModel": "AMD Ryzen 7 5700G with Radeon Graphics ", "totalMemory": "7.40 GB", "freeMemory": "1.00 GB" }, "node": { "version": "v22.20.0", "env": "development" }, "packageManager": { "name": "npm", "version": "10.9.3" }, "frameworks": null, "databases": [ { "name": "pg", "version": "^8.19.0" }, { "name": "@prisma/client", "version": "^7.4.2" } ], "betterAuth": { "version": "^1.4.20", "config": { "url": "http://localhost:3000", "secret": "[REDACTED]", "emailAndPassword": { "enabled": true, "requireEmailVerification": true, "resetPasswordTokenExpiresIn": 300, "revokeSessionsOnPasswordReset": true }, "emailVerification": { "autoSignInAfterVerification": true, "sendOnSignUp": true, "expiresIn": 300 }, "rateLimit": { "enabled": true, "window": 60, "max": 100, "customRules": { "/sign-in/email": { "window": 10, "max": 3 }, "/sign-up/email": { "window": 10, "max": 3 } } }, "advanced": { "ipAddress": { "ipAddressHeaders": [ "x-forwarded-for", "cf-connecting-ip" ] } }, "trustedOrigins": [ "http://localhost:3000" ] } } } ``` ### Which area(s) are affected? (Select all that apply) Backend ### Auth config (if applicable) ```typescript import { betterAuth } from "better-auth" export const auth = betterAuth({ emailAndPassword: { enabled: true }, }); ``` ### Additional context _No response_
GiteaMirror added the credentialsbug labels 2026-04-17 19:52:49 -05:00
Author
Owner

@dosubot[bot] commented on GitHub (Mar 7, 2026):

Hi @mdarkanurl! I'm Dosu and I’m helping the better-auth team.

This is expected behavior starting from better-auth v1.5.2, introduced in PR #8091 to prevent user enumeration attacks.

Since your config has requireEmailVerification: true, the signUpEmail endpoint now returns a 200 OK with a synthetic user object instead of throwing an error for duplicate emails. This prevents attackers from discovering which emails are registered.

To detect duplicate sign-ups, use the new onExistingUserSignUp callback:

emailAndPassword: {
  enabled: true,
  requireEmailVerification: true,
  onExistingUserSignUp: async ({ user }, request) => {
    // Handle duplicate sign-up attempt here
    console.log(`Duplicate sign-up attempt for: ${user.email}`);
  },
}

To restore the old error-throwing behavior (not recommended for security reasons), set autoSignIn: true AND requireEmailVerification: false.

Related issue: #8363 discusses this same behavior change.

To reply, just mention @dosu.


How did I do? Good | Irrelevant | Incorrect | Verbose | Hallucination | Report 🐛 | Other

Chat with Dosu Open in Cursor Join Discord Share on X

<!-- gh-comment-id:4016759126 --> @dosubot[bot] commented on GitHub (Mar 7, 2026): <!-- Greeting --> Hi @mdarkanurl! I'm [Dosu](https://go.dosu.dev/dosubot) and I’m helping the better-auth team. <!-- Answer --> This is **expected behavior** starting from better-auth v1.5.2, introduced in [PR #8091](https://github.com/better-auth/better-auth/pull/8091) to prevent user enumeration attacks. Since your config has `requireEmailVerification: true`, the `signUpEmail` endpoint now returns a 200 OK with a synthetic user object instead of throwing an error for duplicate emails. This prevents attackers from discovering which emails are registered. **To detect duplicate sign-ups**, use the new `onExistingUserSignUp` callback: ```typescript emailAndPassword: { enabled: true, requireEmailVerification: true, onExistingUserSignUp: async ({ user }, request) => { // Handle duplicate sign-up attempt here console.log(`Duplicate sign-up attempt for: ${user.email}`); }, } ``` **To restore the old error-throwing behavior** (not recommended for security reasons), set `autoSignIn: true` AND `requireEmailVerification: false`. Related issue: [#8363](https://github.com/better-auth/better-auth/issues/8363) discusses this same behavior change. <!-- Dosu Comment Footer --> *To reply, just mention [@dosu](https://go.dosu.dev/dosubot).* --- <sup>How did I do? [Good](https://app.dosu.dev/response-feedback/69c775cd-c749-44bf-80c9-3af9b1d7618c?feedback_type=great_response) | [Irrelevant](https://app.dosu.dev/response-feedback/69c775cd-c749-44bf-80c9-3af9b1d7618c?feedback_type=irrelevant_answer) | [Incorrect](https://app.dosu.dev/response-feedback/69c775cd-c749-44bf-80c9-3af9b1d7618c?feedback_type=incorrect_sources) | [Verbose](https://app.dosu.dev/response-feedback/69c775cd-c749-44bf-80c9-3af9b1d7618c?feedback_type=too_verbose) | [Hallucination](https://app.dosu.dev/response-feedback/69c775cd-c749-44bf-80c9-3af9b1d7618c?feedback_type=hallucination) | [Report 🐛](https://app.dosu.dev/response-feedback/69c775cd-c749-44bf-80c9-3af9b1d7618c?feedback_type=bug_report) | [Other](https://app.dosu.dev/response-feedback/69c775cd-c749-44bf-80c9-3af9b1d7618c?feedback_type=other)</sup> [![Chat with Dosu](https://dosu.dev/dosu-chat-badge.svg)](https://app.dosu.dev/cdda13d9-dd27-4d31-b09a-5d8bec92de21/ask?utm_source=github)&nbsp;[![Open in Cursor](https://dosu.dev/dosu-in-cursor.svg)](https://cursor.com/link/prompt?text=This%20is%20%2A%2Aexpected%20behavior%2A%2A%20starting%20from%20better-auth%20v1.5.2%2C%20introduced%20in%20%5BPR%20%238091%5D%28https%3A//github.com/better-auth/better-auth/pull/8091%29%20to%20prevent%20user%20enumeration%20attacks.%0A%0ASince%20your%20config%20has%20%60requireEmailVerification%3A%20true%60%2C%20the%20%60signUpEmail%60%20endpoint%20now%20returns%20a%20200%20OK%20with%20a%20synthetic%20user%20object%20instead%20of%20throwing%20an%20error%20for%20duplicate%20emails.%20This%20prevents%20attackers%20from%20discovering%20which%20emails%20are%20registered.%0A%0A%2A%2ATo%20detect%20duplicate%20sign-ups%2A%2A%2C%20use%20the%20new%20%60onExistingUserSignUp%60%20callback%3A%0A%0A%60%60%60typescript%0AemailAndPassword%3A%20%7B%0A%20%20enabled%3A%20true%2C%0A%20%20requireEmailVerification%3A%20true%2C%0A%20%20onExistingUserSignUp%3A%20async%20%28%7B%20user%20%7D%2C%20request%29%20%3D%3E%20%7B%0A%20%20%20%20//%20Handle%20duplicate%20sign-up%20attempt%20here%0A%20%20%20%20console.log%28%60Duplicate%20sign-up%20attempt%20for%3A%20%24%7Buser.email%7D%60%29%3B%0A%20%20%7D%2C%0A%7D%0A%60%60%60%0A%0A%2A%2ATo%20restore%20the%20old%20error-throwing%20behavior%2A%2A%20%28not%20recommended%20for%20security%20reasons%29%2C%20set%20%60autoSignIn%3A%20true%60%20AND%20%60requireEmailVerification%3A%20false%60.%0A%0ARelated%20issue%3A%20%5B%238363%5D%28https%3A//github.com/better-auth/better-auth/issues/8363%29%20discusses%20this%20same%20behavior%20change.)&nbsp;[![Join Discord](https://img.shields.io/badge/join-5865F2?logo=discord&logoColor=white&label=)](https://go.dosu.dev/discord-bot)&nbsp;[![Share on X](https://img.shields.io/badge/X-share-black)](https://twitter.com/intent/tweet?text=%40dosu_ai%20helped%20me%20solve%20this%20issue!&url=https%3A//github.com/better-auth/better-auth/issues/8480)
Author
Owner

@himself65 commented on GitHub (Mar 9, 2026):

See dosubot's comment

<!-- gh-comment-id:4025834114 --> @himself65 commented on GitHub (Mar 9, 2026): See dosubot's comment
Author
Owner

@asdofindia commented on GitHub (Mar 17, 2026):

I have requireEmailVerification: true because I want to verify email before allowing people

  1. User signs-up with Google via test@example.com
  2. User entry is created for test@example.com
  3. Time passes
  4. User tries to sign-up via email & password with test@example.com
  5. No error is thrown, user never receives an email, there is no way to remind user that they signed up with social sign-in earlier.

Now, I can of course say this is the user's fault.

But also it would be nice to not tie the security functionality to the "requireEmailVerification" flag, or in some ways be able to opt-out of high security OWASP guidelines in contexts where I am dealing with noobs and can trade security for convenience.

Can we introduce a shouldReturnGenericDuplicateResponse: false flag?

<!-- gh-comment-id:4075988471 --> @asdofindia commented on GitHub (Mar 17, 2026): I have requireEmailVerification: true because I want to verify email before allowing people 1. User signs-up with Google via test@example.com 2. User entry is created for test@example.com 3. Time passes 4. User tries to sign-up via email & password with test@example.com 5. No error is thrown, user never receives an email, there is no way to remind user that they signed up with social sign-in earlier. Now, I can of course say this is the user's fault. But also it would be nice to not tie the security functionality to the "requireEmailVerification" flag, or in some ways be able to opt-out of high security OWASP guidelines in contexts where I am dealing with noobs and can trade security for convenience. Can we introduce a `shouldReturnGenericDuplicateResponse: false` flag?
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#28426