Anyway to allow shared emails?
I have a multi-tenant setup, with an extra column "project_id" setup in my schema, with my database itself confining emails to be unique to projects.
Is there any config value I can change to allow sign-ups with existing emails? No matter what I try (so far), I get the error "Sign-up attempt for existing email: ...."
44 Replies
Better Auth email & password auth doesn't allow emails that already exist to sign-up, and it's not configurable. You may want to re-think the project system, as it probably wont work-out using BA unfortunately.
Is it worth me putting a feature request in, or is that something that's never going to change?
This would almost instantly allow for multi-tenant setups
Alternatively, maybe a custom plugin would solve this?
Most people would be using an organization plugin for project structure systems.
You can configure orgs to be per-email if you want 😁
True, organisations are applicable for most use-cases, but this is another layer of grouping on top of that
Can I know your goal?
We've got a b2b2b setup, where:
- company registers with us, and has a dashboard created for them and their domain
- company sells to customers, so all of those customers are only expected to be unique for that dashboard
With emails being enforced to be unique across the entire system, a customer can't have an account on dashboard A, and dashboard B at the same time
Any kinda b2b2b setup will operate the same way, think of any setup where a company offers a reseller service for example
If you can't support this, I can get around this by adding another column to store their real emails, and just setting the original email column to {uuid}@test.com, but that's hacky and means I can't use your pre-built email tools
But honestly, this is by far better than alternatives so I'll do it if I can't figure out another solution here haha
By alternatives I mean authjs etc
Alternatively, allow us to override field values with things we can do with additionalFields, rather than just changing the key of the field
I believe I understand your goal now - and yeah, for sure at another layer above what BA offers.
Just curious, how would signing in work? We'd just check the user's email against every matching email and find a password that matches what they inputted? What happens if both accounts used the same password?
https://github.com/better-auth/better-auth/issues/1248
Just found an existing issue which seems related 🙂
GitHub
Multi-Tenant userbases / updatable user schema · Issue #1248 · be...
Is this suited for github? Yes, this is suited for github Is your feature request related to a problem? Please describe. Hi, I'm looking to create a B2B2C SaaS application with a couple require...
So either the client or server needs to know the tenant
With our system, we look at the host to find a tenant, and then based on that we look at all users that are under that tenant to see if the user exists
So it would have to work async somehow
It doesn't care about the password at this stage
Would this work for your case?

Yeah that would work, it just means we can't use your email tools like signup/user profile change notifications
Thats the only drawback :/
are you referring to useSession? What do you mean profile change notification?
Email | Better Auth
Learn how to use email with Better Auth.
Maybe mis-spoke, thought I saw in the docs somewhere that it would send an email notification upon changing user details
Feel like a potential solution to this problem, which might open up more options, is letting us change default field options in addition to just changing the 'key', similair to what you can do to additionalFields (required, input)
No, I don't believe we do this.
In any case, you can always fetch the user data based on email from your DB, then find their tenant id or whatever, and remove that from the prefix of the email to properly send emails, or do whatever you may want regarding email.
Yeah can do
Just seems hacky is all
I can for sure use it
Yeah, I think this is best-case as far as I can tell. 🤔
Just see this as a potential improvement
For BA so far, that is.
Fair enough mate
You're right. I'll add this to my to-do list and I'll think of solutions on having this built-in.
I'll ping you here if I have any news.
Awesome thank you!
@Platon Just came up with a better idea for the email sending part.
Instead of querying your DB to remove the prefix, you could make each email's prefix use a dash or some special character before the real email, or any special character that couldn't be part of the email prefix.
So instead of querying your DB to find the id and remove said email prefix id, you can just replace everything in front of your special character/dash.
I hope i made sense 😅
Believe I get ya, still think the first solution works fine though
If I know im on tenant 1's site, and their tenant id is 123, if I just query for 123-{restofemail}, then thats my list of users
Or maybe I misunderstood and your new solutions actually better?
Either way actually, because I can't use the built in email system, I'll probably just have a separate column for both email and tenant, then the email column can just be some nonsense like [email protected]
Can I know why you can't use built-in method + the work-around with the prefixed email?
Just wondering since I want to have built-in support for your use-case and maybe this info is helpful
DB searches are going to be slower, and I wouldn't be able to index properly against tenants/emails
DB searches are going to be slowerWith my new idea you won't need to do any additional DB queries. Let me elaborate on my idea. Say you have tenant ids, and say they are only just numbers. When a new user signs up, the email will be
[email protected]
.
Then, say that same user works in a different org, when they sign-up again, it will say [email protected]
.
Instead of querying your DB to find the tenant id
and remove that from the prefix of the email, you can just use JS to remove everything in front of the -
character.
Since you know that the tenant id
is always numbers, and won't include -
.
After removing everything in front of -
in the email, it looks something like this:
[email protected]
-> [email protected]
Yeah I totally get you, i just mean outside of registering, I still need to use the tenant id for certain actions, i.e. say I want to list all the accounts under a tenant
So for that, I'd still have a separate column for tenant id
Which is fine, its just duplication of data
Okay I understand you now. Thanks for your patience by the way :)
Okay yeah, in my idea for built-in support, we'd have a seperate field as well.
It's really just everything I suggested to you as a work-around, but instead built-in lol
So hopefully no additional work on your end.
No, thsank you for being mega helpful and so keen to help me about!
I was just thinking a better, more open ended solution, is to let us override the user matching logic entirely
I know you already have a username plugin, but this method could be used for things like that too
I imagine it as a function that takes in ctx, and spits out a user, and this basicly overrides the internalAdapter.findUserByEmail if set
Might be more trouble in the long run for both devs of Better auth, and users who intend to enable this feature. 🤔
Ok fair enough just a thought
Don't worry - definitely open to ideas
We must keep in mind that a lot of systems could be running on the expectation that emails are unique.
To all internal code, it doesn't matter if the email has a special prefix or not.
However to public-facing code, it does matter - eg displaying email on UI, or sending emails off
The pros of this btw:
- Can replace username login plugin
- Can use this instead of the email login method, just match it with the body.email internally
- Can use for other methods that people might want, i.e. login with phone number / password
- Can be used for all the above together (login with either username, phone number, email)
And finally...
- Can allow for multi tenant setups
There's probably a lot more that I'm not thinking of 🙂
Would it be worth me giving it a go and making a pull request, to see if I can do it cleanly?
It's basically a really flexible solution to logins
Maybe the way the system is built won't handle that easily though
I'm not saying you override existing behaviour, none of that changes, just an config option where it can be overwridden with custom logic to support any type of auth really
Alright sure!
https://github.com/better-auth/better-auth/pull/2342
I'm sure it's a little away from being production ready for you guys, but this is the gist of it basiclly - working locally for my use case perfectly!
Just for context, this is how I'm using it:
findUser: async (ctx) => {
const storeId = getStore(ctx)
console.log({storeId})
const user = await prisma.user.findFirst({
where: {
storeId,
email: ctx.body.email
}
});
console.log({user})
return user;
}
Where the getStore function looks at the Host from the ctx headers, in order to get the storeId
As you can hopefully see though, it leaves it pretty open ended to many other use-cases
Can potentially open it up a bit more by also passing through the function being used as a second parameter to findUser, and based on that, we can throw custom errors if a user is found
I.e. findUser: (ctx, type) => {
...
if (user && type === "signUp") throw new Error("Existing user with the same email found on this store")
My laptops struggling to keep up with typescript on the better-auth project so struggling to see if everything's been applied properly, can give it a better go later if you're fond of the idea?
Just as an idea from someone outside: I'm doing something similar, providing auth for my users and I've went with just providing one better auth instance per customer. I already have separate databases in place so I can move it to different regions for each customer and for some compliance, but if those are not a concern (should be though), you could very well go with separate instances within a single backend with custom table names and basePath per customer. This does involve some setup beforehand due to the migrations, but I'd wager a not 100% at-runtime solution can be accepted for a b2b2b case and if not, you could run migrations at runtime like I do
Sounds way more reasonable than trying to hack around a solution and honestly, opens up so much more flexibility in operations, support and customizability (custom behavior per customer)
I do think this sounds better as it plays more in favour of BA's current system.
@Firro this is the exact system we’re migrating thousands of our customers from, it ends up being really expensive and more difficult to maintain than having on one system
Either way though, the solution I’ve provided offers more flexibility I believe
That system you mentioned would require a complete architectural change, and although it does give many benefits it’s also a lot of work
Good idea though
In the end if BetterAuth wants to be comprehensive then maybe we can support it directly.
On the other hand, what you guys are asking for is basically an auth provider solution. Instead of our framework handling your users, you're asking our framework to handle the users of your users.
Beacuse of this I'm not 100% certain on it being built in, but I do want to help find a really solid solution that can cover the grounds we want while not being too expensive and hard to setup
Totally get ya
Did you see the fork I sent over ?
Totally appreciate all the time you’ve spent on this so far
I don’t expect this to be a built in solution as it’s kinda niche, however think the findUser solution is pretty open ended and can solve other problems at the same time
Hey, wanted to jump in to say I am also building a sort of B2B2B marketplace and was weighing whether it would better to give each "partner" their own portal and it looks like that is currently not possible.
Would it be possible to have a native plugin that adds an organization/portal field in the user/account table and overrides the unique email constraint, replacing it with a unique on [email & organization/portal]. This would allow us to have multiple auth portals in the same database and enable programmatic portal creation, etc. Allowing one person with the same credentials to authenticate through a second portal, as well.
Not 100% sure on the exact implementation details, but I believe this would suffice for my use case. Along the lines of this conversation a much more niche but equally useful feature in auth systems are organization composition/nesting, where an organization can be the owner of many organizations. I am not sure if this is possible currently, and ideally organization composition also allowed for scoped permissions + scoped auth portals, as well.
Would it be possible to have a native plugin that adds an organization/portal field in the user/account table and overrides the unique email constraintI don't think so.
where an organization can be the owner of many organizationsyeah, orgs within orgs are not currently supported.