fix: throw on duplicate email when autoSignIn: false without requireEmailVerification (#8521)

This commit is contained in:
Alex Yang
2026-03-10 15:03:39 -07:00
parent 5003d94673
commit e3e6664d7b
2 changed files with 59 additions and 7 deletions
@@ -265,13 +265,14 @@ describe("sign-up user enumeration protection", async () => {
);
});
it("should call onExistingUserSignUp when autoSignIn is false", async () => {
it("should call onExistingUserSignUp when autoSignIn is false and requireEmailVerification is true", async () => {
const onExistingUserSignUp = vi.fn();
const { auth } = await getTestInstance(
{
emailAndPassword: {
enabled: true,
autoSignIn: false,
requireEmailVerification: true,
onExistingUserSignUp,
},
},
@@ -292,6 +293,33 @@ describe("sign-up user enumeration protection", async () => {
expect(onExistingUserSignUp).toHaveBeenCalledTimes(1);
});
it("should not call onExistingUserSignUp when autoSignIn is false without requireEmailVerification", async () => {
const onExistingUserSignUp = vi.fn();
const { auth } = await getTestInstance(
{
emailAndPassword: {
enabled: true,
autoSignIn: false,
onExistingUserSignUp,
},
},
{
disableTestUser: true,
},
);
const body = {
email: "callback-autosignin-no-verify@test.com",
password: "password123",
name: "Callback AutoSignIn No Verify",
};
await auth.api.signUpEmail({ body });
await expect(auth.api.signUpEmail({ body })).rejects.toThrow();
expect(onExistingUserSignUp).not.toHaveBeenCalled();
});
it("should not call onExistingUserSignUp when enumeration protection is inactive", async () => {
const onExistingUserSignUp = vi.fn();
const { auth } = await getTestInstance(
@@ -344,7 +372,7 @@ describe("sign-up user enumeration protection", async () => {
expect(onExistingUserSignUp).not.toHaveBeenCalled();
});
it("should return success for existing email when autoSignIn is disabled", async () => {
it("should throw for existing email when autoSignIn is disabled without requireEmailVerification", async () => {
const { auth } = await getTestInstance(
{
emailAndPassword: {
@@ -365,10 +393,32 @@ describe("sign-up user enumeration protection", async () => {
await auth.api.signUpEmail({ body });
const duplicatedSignUp = await auth.api.signUpEmail({ body });
await expect(auth.api.signUpEmail({ body })).rejects.toThrow();
});
expect(duplicatedSignUp.token).toBeNull();
expect(duplicatedSignUp.user.email).toBe(body.email);
it("should return token: null for new sign-up when autoSignIn is disabled", async () => {
const { auth } = await getTestInstance(
{
emailAndPassword: {
enabled: true,
autoSignIn: false,
},
},
{
disableTestUser: true,
},
);
const res = await auth.api.signUpEmail({
body: {
email: "new-auto-signin@test.com",
password: "password123",
name: "New User",
},
});
expect(res.token).toBeNull();
expect(res.user.email).toBe("new-auto-signin@test.com");
});
});
@@ -232,8 +232,10 @@ export const signUpEmail = <O extends BetterAuthOptions>() =>
);
}
const shouldReturnGenericDuplicateResponse =
ctx.context.options.emailAndPassword.autoSignIn === false ||
ctx.context.options.emailAndPassword.requireEmailVerification;
const shouldSkipAutoSignIn =
ctx.context.options.emailAndPassword.autoSignIn === false ||
shouldReturnGenericDuplicateResponse;
const additionalUserFields = parseUserInput(
ctx.context.options,
rest,
@@ -391,7 +393,7 @@ export const signUpEmail = <O extends BetterAuthOptions>() =>
}
}
if (shouldReturnGenericDuplicateResponse) {
if (shouldSkipAutoSignIn) {
return ctx.json({
token: null,
user: parseUserOutput(ctx.context.options, createdUser) as User<