[GH-ISSUE #2777] Password Reset with Unregistered Email Returns True Status, No Error Message Displayed #17976

Closed
opened 2026-04-15 16:20:31 -05:00 by GiteaMirror · 3 comments
Owner

Originally created by @shresthapradhuman on GitHub (May 24, 2025).
Original GitHub issue: https://github.com/better-auth/better-auth/issues/2777

Is this suited for github?

  • Yes, this is suited for github

To Reproduce

Description:

When attempting to reset a password using an email address that is not registered in the system, the better-auth library returns a response with a status of true instead of an error. This prevents the error message from being displayed to the user, leading to a poor user experience as users are not informed that the email is not registered.

To Reproduce:

  1. Use a better-auth integrated application with email and password authentication enabled.
  2. Navigate to the password reset page or trigger the password reset flow.
  3. Enter an email address that is not registered in the system.
  4. Submit the password reset request.
  5. Observe the response from the authClient.resetPassword or similar API call.

Current vs. Expected behavior

Expected Behavior:

  1. The system should return an error response (e.g., status: false or an error object) indicating that the email is not registered.
  2. An error message should be displayed to the user, such as "Email not found" or "No account associated with this email."

Actual Behavior:

  1. The response returns status: true (or equivalent success status) even for unregistered emails.
  2. No error message is displayed to the user, leading to confusion as the password reset appears to proceed without feedback.

What version of Better Auth are you using?

^1.2.8

Provide environment information

- OS Mac Sequoia 15.4
- Framework NextJS 15.3.2
- Database neon PostgreSQL
- Prisma ORM
- nodejs 22.11.0
- Browser Google Chrome
- Other Dependencies (React Hook Form, Zod, Shadcn Form)

Here’s an example of how the password reset is likely implemented (based on similar issues):

const onSubmit = async (data: z.infer<typeof resetPasswordSchema>) => {
  setIsPending(true);
  const { error } = await authClient.resetPassword({
    email: data.email, // Unregistered email entered here
  });
  if (error) {
    toast({
      title: "Error",
      description: error.message,
      variant: "destructive",
    });
  } else {
    toast({
      title: "Success",
      description: "Password reset email sent successfully.",
    });
  }
  setIsPending(false);
};

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

Package

Auth config (if applicable)

import { betterAuth, BetterAuthOptions } from 'better-auth'
import { prismaAdapter } from 'better-auth/adapters/prisma'
import { prisma } from './prisma/client'
import { openAPI } from 'better-auth/plugins'
import { resend } from './lib/resend'
import { EmailVerification } from './templates/EmailVerification'
import ResetPassword from './templates/ResetPassword'

export const auth = betterAuth({
  database: prismaAdapter(prisma, {
    provider: 'postgresql',
  }),
  session: {
    expiresIn: 60 * 60 * 24 * 7,
    cookieCache: {
      enabled: true,
      maxAge: 5 * 60,
    },
  },
  user: {
    additionalFields: {
      contact: {
        type: 'string',
      },
      bio: {
        type: 'string',
      },
    },
  },
  emailAndPassword: {
    enabled: true,
    minPasswordLength: 6,
    requireEmailVerification: true,
    sendResetPassword: async ({ user, url }) => {
      await resend.emails.send({
        from: 'onboarding@resend.dev',
        to: user.email,
        subject: 'Reset Forgot Password',
        react: ResetPassword({
          url,
          name: user?.name,
        }),
      })
    },
  },
  emailVerification: {
    sendOnSignUp: true,
    expiresIn: 60 * 60,
    autoSignInAfterVerification: true,
    sendVerificationEmail: async ({ user, url }) => {
      const link = new URL(url)
      link.searchParams.set('callbackURL', '/email-verified')
      await resend.emails.send({
        from: 'onboarding@resend.dev',
        to: user.email,
        subject: 'Email Verification',
        react: EmailVerification(String(link), user.name),
      })
    },
  },
  socialProviders: {
    google: {
      prompt: 'select_account',
      clientId: process.env.GOOGLE_CLIENT_ID as string,
      clientSecret: process.env.GOOGLE_CLIENT_SECRET as string,
    },
  },
  account: {
    accountLinking: {
      enabled: false,
    },
  },
  plugins: [openAPI()],
} satisfies BetterAuthOptions)

export type Session = typeof auth.$Infer.Session

Additional context

Additional Context:

  • The authClient.forgotPassword function does not seem to validate whether the provided email exists in the database before returning a success response.
  • This issue may be related to the configuration in better-auth for the emailAndPassword option, specifically the sendResetPassword function, which might not be properly handling unregistered emails.

suggested Fix:
ForgotPassword Api is check the user but not returning the message. so, message should be return along with status false.

Originally created by @shresthapradhuman on GitHub (May 24, 2025). Original GitHub issue: https://github.com/better-auth/better-auth/issues/2777 ### Is this suited for github? - [x] Yes, this is suited for github ### To Reproduce Description: When attempting to reset a password using an email address that is not registered in the system, the better-auth library returns a response with a status of true instead of an error. This prevents the error message from being displayed to the user, leading to a poor user experience as users are not informed that the email is not registered. To Reproduce: 1. Use a better-auth integrated application with email and password authentication enabled. 2. Navigate to the password reset page or trigger the password reset flow. 3. Enter an email address that is not registered in the system. 4. Submit the password reset request. 5. Observe the response from the authClient.resetPassword or similar API call. ### Current vs. Expected behavior Expected Behavior: 1. The system should return an error response (e.g., status: false or an error object) indicating that the email is not registered. 2. An error message should be displayed to the user, such as "Email not found" or "No account associated with this email." Actual Behavior: 1. The response returns status: true (or equivalent success status) even for unregistered emails. 2. No error message is displayed to the user, leading to confusion as the password reset appears to proceed without feedback. ### What version of Better Auth are you using? ^1.2.8 ### Provide environment information ```bash - OS Mac Sequoia 15.4 - Framework NextJS 15.3.2 - Database neon PostgreSQL - Prisma ORM - nodejs 22.11.0 - Browser Google Chrome - Other Dependencies (React Hook Form, Zod, Shadcn Form) Here’s an example of how the password reset is likely implemented (based on similar issues): const onSubmit = async (data: z.infer<typeof resetPasswordSchema>) => { setIsPending(true); const { error } = await authClient.resetPassword({ email: data.email, // Unregistered email entered here }); if (error) { toast({ title: "Error", description: error.message, variant: "destructive", }); } else { toast({ title: "Success", description: "Password reset email sent successfully.", }); } setIsPending(false); }; ``` ### Which area(s) are affected? (Select all that apply) Package ### Auth config (if applicable) ```typescript import { betterAuth, BetterAuthOptions } from 'better-auth' import { prismaAdapter } from 'better-auth/adapters/prisma' import { prisma } from './prisma/client' import { openAPI } from 'better-auth/plugins' import { resend } from './lib/resend' import { EmailVerification } from './templates/EmailVerification' import ResetPassword from './templates/ResetPassword' export const auth = betterAuth({ database: prismaAdapter(prisma, { provider: 'postgresql', }), session: { expiresIn: 60 * 60 * 24 * 7, cookieCache: { enabled: true, maxAge: 5 * 60, }, }, user: { additionalFields: { contact: { type: 'string', }, bio: { type: 'string', }, }, }, emailAndPassword: { enabled: true, minPasswordLength: 6, requireEmailVerification: true, sendResetPassword: async ({ user, url }) => { await resend.emails.send({ from: 'onboarding@resend.dev', to: user.email, subject: 'Reset Forgot Password', react: ResetPassword({ url, name: user?.name, }), }) }, }, emailVerification: { sendOnSignUp: true, expiresIn: 60 * 60, autoSignInAfterVerification: true, sendVerificationEmail: async ({ user, url }) => { const link = new URL(url) link.searchParams.set('callbackURL', '/email-verified') await resend.emails.send({ from: 'onboarding@resend.dev', to: user.email, subject: 'Email Verification', react: EmailVerification(String(link), user.name), }) }, }, socialProviders: { google: { prompt: 'select_account', clientId: process.env.GOOGLE_CLIENT_ID as string, clientSecret: process.env.GOOGLE_CLIENT_SECRET as string, }, }, account: { accountLinking: { enabled: false, }, }, plugins: [openAPI()], } satisfies BetterAuthOptions) export type Session = typeof auth.$Infer.Session ``` ### Additional context Additional Context: - The authClient.forgotPassword function does not seem to validate whether the provided email exists in the database before returning a success response. - This issue may be related to the configuration in better-auth for the emailAndPassword option, specifically the sendResetPassword function, which might not be properly handling unregistered emails. suggested Fix: ForgotPassword Api is check the user but not returning the message. so, message should be return along with status false.
GiteaMirror added the locked label 2026-04-15 16:20:31 -05:00
Author
Owner

@aynaash commented on GitHub (May 25, 2025):

Hey can i work on this please?

<!-- gh-comment-id:2907654564 --> @aynaash commented on GitHub (May 25, 2025): Hey can i work on this please?
Author
Owner

@shresthapradhuman commented on GitHub (May 25, 2025):

Hey can i work on this please?

Yes, please.

<!-- gh-comment-id:2907910050 --> @shresthapradhuman commented on GitHub (May 25, 2025): > Hey can i work on this please? Yes, please.
Author
Owner

@aynaash commented on GitHub (May 26, 2025):

okay

<!-- gh-comment-id:2909813417 --> @aynaash commented on GitHub (May 26, 2025): okay
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#17976