[GH-ISSUE #2160] Signup with email OTP #9073

Closed
opened 2026-04-13 04:22:34 -05:00 by GiteaMirror · 5 comments
Owner

Originally created by @coderrshyam on GitHub (Apr 7, 2025).
Original GitHub issue: https://github.com/better-auth/better-auth/issues/2160

Is this suited for github?

  • Yes, this is suited for github

When a user use plugin emailOTP but not email and password . It is easy to signIn and very email using emailOTP but what happens when user enabled field sendVerificationOnSignUp so there is built in method inside emailOTP to signup just like:

emailOTP.signup({
email: "test@abcd.com"
otp: "565656"
})

If otp is correct then user sign-ins automatically and the type should also includes 'sign-up' along with defaults 'sign-in' .....

Describe the solution you'd like

I had like if emailOTP supports built-in sign-up process just like sign-in. let's take a situation if user verified their email with otp then how it signIn because the type is 'email-verification' so when signIn attempts it throw error invalid otp.

Describe alternatives you've considered

I think there is no alternative of that. this feature pushes better-auth to height.

Additional context

No response

Originally created by @coderrshyam on GitHub (Apr 7, 2025). Original GitHub issue: https://github.com/better-auth/better-auth/issues/2160 ### Is this suited for github? - [x] Yes, this is suited for github ### Is your feature request related to a problem? Please describe. When a user use plugin `emailOTP` but not `email and password` . It is easy to signIn and very email using `emailOTP` but what happens when user enabled field `sendVerificationOnSignUp` so there is built in method inside emailOTP to signup just like: ``` emailOTP.signup({ email: "test@abcd.com" otp: "565656" }) ``` If otp is correct then user sign-ins automatically and the type should also includes 'sign-up' along with defaults 'sign-in' ..... ### Describe the solution you'd like I had like if emailOTP supports built-in sign-up process just like sign-in. let's take a situation if user verified their email with otp then how it signIn because the type is 'email-verification' so when signIn attempts it throw error invalid otp. ### Describe alternatives you've considered I think there is no alternative of that. this feature pushes better-auth to height. ### Additional context _No response_
GiteaMirror added the locked label 2026-04-13 04:22:34 -05:00
Author
Owner

@SDGomez1 commented on GitHub (May 20, 2025):

I've been looking into this and have found a potential workaround using the existing emailOTP plugin functionality that might address the sign-up flow you're looking for.

It seems you can leverage the emailVerification.autoSignInAfterVerification: true flag in the betterAuth configuration. When this is enabled, after a user successfully verifies their email, better-auth automatically creates a session for them.

Then, within the emailOTP plugin's sendVerificationOTP function, you can kinda differentiate between sign-in and sign-up scenarios based on the type parameter:

  • For sign-up: When type is 'sign-in', you can check if a user with that email does not already exist in your database using your database/user service. If they don't, proceed with sending the OTP using your notification service. After they verify this 'sign-in' type OTP, the default config would create the user in your db. As you write the logic you can avoid sending the OTP when the users already have an account.
  • For sign-in: When type is 'email-verification', you would check if a user with that email does exist in your database. If they do, send the OTP for email verification of their existing account using your notification service. because autoSignInAfterVerification is true, they will be automatically signed in. Same logic here, you can avoid sending the otp if the user doesn't have an account.

Here's how that might look in the betterAuth config:

betterAuth({
  // ... other better-auth configuration
  emailVerification: {
    autoSignInAfterVerification: true, // Crucial for automatically signing in after verification
  },

  plugins: [
    emailOTP({
      async sendVerificationOTP({ email, otp, type }) {
        if (type === "sign-in") {
          // Logic to check if user exists for a potential sign-up
          const userExists = await checkIfUserExistsByEmail(email); // query your db to check  for this user

          if (!userExists) {
            console.log(`Sending sign-up OTP ${otp} to ${email}`);
            // Logic to send the OTP for new user registration
            await sendEmail(email, otp); // your send function
          } else {
            console.log(`User ${email} found, not sending sign-in OTP (or handle existing user sign-in flow)`);
          }
        } else if (type === "email-verification") {
          // Logic to check if user exists for signIn
          const userExists = await checkIfUserExistsByEmail(email);

          if (userExists) {
            console.log(`Sending email verification OTP ${otp} to ${email}`);
            // Logic to send the OTP to verify an existing user's email
            await sendEmail(email, otp'); // your send function
          } else {
            console.log(`No user found, no email sent for ${email}`);
          }
        } 
      },
    }),
  ],
});

So in the client side, for a sign in you call:

//When first sending the OTP
authClient.emailOtp.sendVerificationOtp({
   email: data.email,
   type: "email-verification",
});

//When validating the OTP
authClient.emailOtp.verifyEmail({
    email: userEmail,
    otp: userOtp,
});

And for a sign up:

//When first sending the OTP
authClient.emailOtp.sendVerificationOtp({
     email: data.email,
     type: "sign-in",
});

//When validating the OTP
authClient.signIn.emailOtp({
     email: userEmail,
     otp: userOtp,
});

Hope this helps

<!-- gh-comment-id:2892961138 --> @SDGomez1 commented on GitHub (May 20, 2025): I've been looking into this and have found a potential workaround using the existing `emailOTP` plugin functionality that might address the sign-up flow you're looking for. It seems you can leverage the `emailVerification.autoSignInAfterVerification: true` flag in the `betterAuth` configuration. When this is enabled, after a user successfully verifies their email, better-auth automatically creates a session for them. Then, within the `emailOTP` plugin's `sendVerificationOTP` function, you can kinda differentiate between sign-in and sign-up scenarios based on the `type` parameter: * **For sign-up:** When `type` is `'sign-in'`, you can check if a user with that email **does not** already exist in your database using your database/user service. If they don't, proceed with sending the OTP using your notification service. After they verify this 'sign-in' type OTP, the default config would create the user in your db. As you write the logic you can avoid sending the OTP when the users already have an account. * **For sign-in:** When `type` is `'email-verification'`, you would check if a user with that email **does** exist in your database. If they do, send the OTP for email verification of their existing account using your notification service. because `autoSignInAfterVerification` is true, they will be automatically signed in. Same logic here, you can avoid sending the otp if the user doesn't have an account. Here's how that might look in the `betterAuth` config: ```typescript betterAuth({ // ... other better-auth configuration emailVerification: { autoSignInAfterVerification: true, // Crucial for automatically signing in after verification }, plugins: [ emailOTP({ async sendVerificationOTP({ email, otp, type }) { if (type === "sign-in") { // Logic to check if user exists for a potential sign-up const userExists = await checkIfUserExistsByEmail(email); // query your db to check for this user if (!userExists) { console.log(`Sending sign-up OTP ${otp} to ${email}`); // Logic to send the OTP for new user registration await sendEmail(email, otp); // your send function } else { console.log(`User ${email} found, not sending sign-in OTP (or handle existing user sign-in flow)`); } } else if (type === "email-verification") { // Logic to check if user exists for signIn const userExists = await checkIfUserExistsByEmail(email); if (userExists) { console.log(`Sending email verification OTP ${otp} to ${email}`); // Logic to send the OTP to verify an existing user's email await sendEmail(email, otp'); // your send function } else { console.log(`No user found, no email sent for ${email}`); } } }, }), ], }); ``` So in the client side, for a sign in you call: ```typescript //When first sending the OTP authClient.emailOtp.sendVerificationOtp({ email: data.email, type: "email-verification", }); //When validating the OTP authClient.emailOtp.verifyEmail({ email: userEmail, otp: userOtp, }); ``` And for a sign up: ```typescript //When first sending the OTP authClient.emailOtp.sendVerificationOtp({ email: data.email, type: "sign-in", }); //When validating the OTP authClient.signIn.emailOtp({ email: userEmail, otp: userOtp, }); ``` Hope this helps
Author
Owner

@coderrshyam commented on GitHub (May 20, 2025):

Hmm! Sounds Good. Let me try

<!-- gh-comment-id:2892966408 --> @coderrshyam commented on GitHub (May 20, 2025): Hmm! Sounds Good. Let me try
Author
Owner

@rogueturnip commented on GitHub (Jun 8, 2025):

I wanted to ask if you found this process to work for you. i’m looking at something similar that will create the user if they don’t exist.

<!-- gh-comment-id:2954314315 --> @rogueturnip commented on GitHub (Jun 8, 2025): I wanted to ask if you found this process to work for you. i’m looking at something similar that will create the user if they don’t exist.
Author
Owner

@budivoogt commented on GitHub (Jul 3, 2025):

I'm using the emailOTP plugin and implemented all this server-side. The autoSignIn worked when I additionally passed:

export const auth = betterAuth({
			emailVerification: {
		autoSignInAfterVerification: true
	},

Make sure to pass the headers to all server-side requests and to have configured a way to pass cookies to the client.

<!-- gh-comment-id:3033441774 --> @budivoogt commented on GitHub (Jul 3, 2025): I'm using the emailOTP plugin and implemented all this server-side. The autoSignIn worked when I additionally passed: ``` export const auth = betterAuth({ emailVerification: { autoSignInAfterVerification: true }, ``` Make sure to pass the headers to all server-side requests and to have configured a way to pass cookies to the client.
Author
Owner

@karan042 commented on GitHub (Dec 24, 2025):

Is this a WONTFIX from the better-auth team and is https://github.com/better-auth/better-auth/issues/2160#issuecomment-2892961138 the only possible way to achieve this?

<!-- gh-comment-id:3689382217 --> @karan042 commented on GitHub (Dec 24, 2025): Is this a WONTFIX from the better-auth team and is https://github.com/better-auth/better-auth/issues/2160#issuecomment-2892961138 the only possible way to achieve this?
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#9073