[GH-ISSUE #2215] Email address is required, but what should I do if the user doesn’t have an email address? #9105

Closed
opened 2026-04-13 04:26:12 -05:00 by GiteaMirror · 12 comments
Owner

Originally created by @quentin996007 on GitHub (Apr 10, 2025).
Original GitHub issue: https://github.com/better-auth/better-auth/issues/2215

I saw the documentation saying this
Email is a key part of Better Auth, required for all users regardless of their authentication method. Better Auth provides email and password authentication out of the box, and a lot of utilities to help you manage email verification, password reset, and more.
However, some users do not have the habit of using email. They do not have email. Usually, they register and log in with their mobile phone number and verification code for identity authentication. If there is no email, how should I deal with this Email required option? For example, I want to use username or phone as the only credential.

Originally created by @quentin996007 on GitHub (Apr 10, 2025). Original GitHub issue: https://github.com/better-auth/better-auth/issues/2215 I saw the documentation saying this **Email is a key part of Better Auth, required for all users regardless of their authentication method. Better Auth provides email and password authentication out of the box, and a lot of utilities to help you manage email verification, password reset, and more.** However, some users do not have the habit of using email. They do not have email. Usually, they register and log in with their mobile phone number and verification code for identity authentication. If there is no email, how should I deal with this `Email` required option? For example, I want to use `username` or `phone` as the only credential.
GiteaMirror added the locked label 2026-04-13 04:26:13 -05:00
Author
Owner

@pcamarajr commented on GitHub (Apr 10, 2025):

You can use the Phone Number plugin.

There's even other options, such as passkey or Google on tap that can also be useful.

<!-- gh-comment-id:2795164232 --> @pcamarajr commented on GitHub (Apr 10, 2025): You can use the [Phone Number](https://www.better-auth.com/docs/plugins/phone-number) plugin. There's even other options, such as [passkey](https://www.better-auth.com/docs/plugins/passkey) or [Google on tap](https://www.better-auth.com/docs/plugins/one-tap) that can also be useful.
Author
Owner

@quentin996007 commented on GitHub (Apr 10, 2025):

You can use the Phone Number plugin.

There's even other options, such as passkey or Google on tap that can also be useful.

So can I omit the email field? I see the document saying that this field must exist regardless of the validation method

<!-- gh-comment-id:2795224139 --> @quentin996007 commented on GitHub (Apr 10, 2025): > You can use the [Phone Number](https://www.better-auth.com/docs/plugins/phone-number) plugin. > > There's even other options, such as [passkey](https://www.better-auth.com/docs/plugins/passkey) or [Google on tap](https://www.better-auth.com/docs/plugins/one-tap) that can also be useful. So can I omit the email field? I see the document saying that this field must exist regardless of the validation method
Author
Owner

@Kinfe123 commented on GitHub (Apr 11, 2025):

You can generate a temp email like this for soft pass

 plugins: [
    phoneNumber({
      // Generate a temporary email for internal use
      signUpOnVerification: {
        getTempEmail: (phoneNumber) => `${phoneNumber}@temp.domain`,
        getTempName: (phoneNumber) => `User ${phoneNumber}`
      },
      sendOTP: async ({ phoneNumber, code }) => {
        // Implement your SMS service here
      },
      callbackOnVerification: async ({ phoneNumber, user }) => {
        // Handle post-verification logic
      }
    })
  ],


<!-- gh-comment-id:2795812114 --> @Kinfe123 commented on GitHub (Apr 11, 2025): You can generate a temp email like this for soft pass ```ts plugins: [ phoneNumber({ // Generate a temporary email for internal use signUpOnVerification: { getTempEmail: (phoneNumber) => `${phoneNumber}@temp.domain`, getTempName: (phoneNumber) => `User ${phoneNumber}` }, sendOTP: async ({ phoneNumber, code }) => { // Implement your SMS service here }, callbackOnVerification: async ({ phoneNumber, user }) => { // Handle post-verification logic } }) ], ```
Author
Owner

@quentin996007 commented on GitHub (Apr 11, 2025):

You can generate a temp email like this for soft pass

plugins: [
phoneNumber({
// Generate a temporary email for internal use
signUpOnVerification: {
getTempEmail: (phoneNumber) => ${phoneNumber}@temp.domain,
getTempName: (phoneNumber) => User ${phoneNumber}
},
sendOTP: async ({ phoneNumber, code }) => {
// Implement your SMS service here
},
callbackOnVerification: async ({ phoneNumber, user }) => {
// Handle post-verification logic
}
})
],

https://www.better-auth.com/docs/plugins/username If I register with username, I have to build a temporary email myself, right? I feel a little strange this way, because the email field in the database cannot distinguish which is a formal email and which is a temporary email. I think a better way is for email to be empty. If I use the username phone plug-in, as long as one of email/username/phone has a value, will it be better?

<!-- gh-comment-id:2795916944 --> @quentin996007 commented on GitHub (Apr 11, 2025): > You can generate a temp email like this for soft pass > > plugins: [ > phoneNumber({ > // Generate a temporary email for internal use > signUpOnVerification: { > getTempEmail: (phoneNumber) => `${phoneNumber}@temp.domain`, > getTempName: (phoneNumber) => `User ${phoneNumber}` > }, > sendOTP: async ({ phoneNumber, code }) => { > // Implement your SMS service here > }, > callbackOnVerification: async ({ phoneNumber, user }) => { > // Handle post-verification logic > } > }) > ], `https://www.better-auth.com/docs/plugins/username` If I register with `username`, I have to build a temporary `email` myself, right? I feel a little strange this way, because the `email` field in the database cannot distinguish which is a formal email and which is a temporary email. I think a better way is for email to be empty. If I use the `username` `phone` plug-in, as long as one of email/username/phone has a value, will it be better?
Author
Owner

@Kinfe123 commented on GitHub (Apr 11, 2025):

as long as you have an field that uniquely identifies it other than email while using a plugins like phone number or sth .. you should be fine you can even later on update if you have to

<!-- gh-comment-id:2795988481 --> @Kinfe123 commented on GitHub (Apr 11, 2025): as long as you have an field that uniquely identifies it other than email while using a plugins like phone number or sth .. you should be fine you can even later on update if you have to
Author
Owner

@quentin996007 commented on GitHub (Apr 11, 2025):

as long as you have an field that uniquely identifies it other than email while using a plugins like phone number or sth .. you should be fine you can even later on update if you have to

So I can set a phone number to be the only credential, and I can make the email field optional in Prisma, or delete it. That's what that means, right?

<!-- gh-comment-id:2796543627 --> @quentin996007 commented on GitHub (Apr 11, 2025): > as long as you have an field that uniquely identifies it other than email while using a plugins like phone number or sth .. you should be fine you can even later on update if you have to So I can set a phone number to be the only credential, and I can make the email field optional in Prisma, or delete it. That's what that means, right?
Author
Owner

@Kinfe123 commented on GitHub (Apr 12, 2025):

since email field comes with emailVerified column later on if you want to use as primary identifier you can just make sure to enable that for using it as identifier. since we are working on making field as extendible as possible... this might be the workaround that i can refer you atm.

<!-- gh-comment-id:2798455910 --> @Kinfe123 commented on GitHub (Apr 12, 2025): since email field comes with emailVerified column later on if you want to use as primary identifier you can just make sure to enable that for using it as identifier. since we are working on making field as extendible as possible... this might be the workaround that i can refer you atm.
Author
Owner

@Nafis2003 commented on GitHub (Apr 12, 2025):

I'm also working on implementing phone number and password authentication in my app. Going through the docs, I noticed that it treats the phone number as a temporary email, which feels like a workaround. It would be easier if there were a straightforward way to handle phone number sign-up, similar to how email sign-up is managed.

<!-- gh-comment-id:2798920038 --> @Nafis2003 commented on GitHub (Apr 12, 2025): I'm also working on implementing phone number and password authentication in my app. Going through the docs, I noticed that it treats the phone number as a temporary email, which feels like a workaround. It would be easier if there were a straightforward way to handle phone number sign-up, similar to how email sign-up is managed.
Author
Owner

@quentin996007 commented on GitHub (Apr 12, 2025):

I'm also working on implementing phone number and password authentication in my app. Going through the docs, I noticed that it treats the phone number as a temporary email, which feels like a workaround. It would be easier if there were a straightforward way to handle phone number sign-up, similar to how email sign-up is managed.

Yes, I am also confused because I have to manually generate an invalid temporary email. obviously the user does not have an email and I want it to show up as null to indicate that the user does not have an email but he has a cell phone number. If I assign the temporary email, there is also the possibility of sending an email to this unavailable temporary email by mistake, causing unintended behavior.

<!-- gh-comment-id:2798943037 --> @quentin996007 commented on GitHub (Apr 12, 2025): > I'm also working on implementing phone number and password authentication in my app. Going through the docs, I noticed that it treats the phone number as a temporary email, which feels like a workaround. It would be easier if there were a straightforward way to handle phone number sign-up, similar to how email sign-up is managed. Yes, I am also confused because I have to manually generate an invalid temporary email. obviously the user does not have an email and I want it to show up as null to indicate that the user does not have an email but he has a cell phone number. If I assign the temporary email, there is also the possibility of sending an email to this unavailable temporary email by mistake, causing unintended behavior.
Author
Owner

@Kinfe123 commented on GitHub (Apr 12, 2025):

since the email is not verified i dont think that would create you a problem if you a user want to be verified you have make sure to send verification email and get verified. but if the email is still the temporary email we will still try to send the verification to that .. this is all upto the user who wants to use the app and we do have a ratelimits set up on that so that you can turn and do guarding on that

<!-- gh-comment-id:2799016417 --> @Kinfe123 commented on GitHub (Apr 12, 2025): since the email is not verified i dont think that would create you a problem if you a user want to be verified you have make sure to send verification email and get verified. but if the email is still the temporary email we will still try to send the verification to that .. this is all upto the user who wants to use the app and we do have a ratelimits set up on that so that you can turn and do guarding on that
Author
Owner

@Kinfe123 commented on GitHub (Apr 12, 2025):

but with that said , we are working to make sure to it is customizable as well.

<!-- gh-comment-id:2799016841 --> @Kinfe123 commented on GitHub (Apr 12, 2025): but with that said , we are working to make sure to it is customizable as well.
Author
Owner

@jeffoxd commented on GitHub (Mar 5, 2026):

For people looking for a oauth solution, you can just use the mapProfileToUser function:

server auth:

    discord: {
      clientId: "REDACTED",
      clientSecret: "REDACTED",
      disableDefaultScope: true,
      scope: ["identify", "guilds.members.read"],
      mapProfileToUser: (profile) => {
        return {
          email: `${profile.id}@example.com`,
          emailVerified: false,
          discordUid: profile.id,
        };
      },
    },
  },

you need to disableDefaultScope because better-auth will have email as default. What mapProfileToUser does is it runs everytime you oauth login, you can even add to additional columns this way. Here I'm using discord UID but you can use anything really (like UUIDv4 or timestamp + name)

<!-- gh-comment-id:4002936840 --> @jeffoxd commented on GitHub (Mar 5, 2026): For people looking for a oauth solution, you can just use the `mapProfileToUser` function: server auth: ```socialProviders: { discord: { clientId: "REDACTED", clientSecret: "REDACTED", disableDefaultScope: true, scope: ["identify", "guilds.members.read"], mapProfileToUser: (profile) => { return { email: `${profile.id}@example.com`, emailVerified: false, discordUid: profile.id, }; }, }, }, ``` you need to `disableDefaultScope` because better-auth will have email as default. What `mapProfileToUser` does is it runs everytime you oauth login, you can even add to additional columns this way. Here I'm using discord UID but you can use anything really (like UUIDv4 or timestamp + name)
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#9105