mirror of
https://github.com/LukeHagar/better-auth.git
synced 2025-12-07 04:19:22 +00:00
fix(better-auth): moved email verification check after password check (#4835)
This commit is contained in:
@@ -286,43 +286,6 @@ export const username = (options?: UsernameOptions) => {
|
||||
});
|
||||
}
|
||||
|
||||
if (
|
||||
ctx.context.options?.emailAndPassword?.requireEmailVerification &&
|
||||
!user.emailVerified
|
||||
) {
|
||||
if (
|
||||
!ctx.context.options?.emailVerification?.sendVerificationEmail
|
||||
) {
|
||||
throw new APIError("FORBIDDEN", {
|
||||
message: ERROR_CODES.EMAIL_NOT_VERIFIED,
|
||||
});
|
||||
}
|
||||
|
||||
if (ctx.context.options?.emailVerification?.sendOnSignIn) {
|
||||
const token = await createEmailVerificationToken(
|
||||
ctx.context.secret,
|
||||
user.email,
|
||||
undefined,
|
||||
ctx.context.options.emailVerification?.expiresIn,
|
||||
);
|
||||
const url = `${ctx.context.baseURL}/verify-email?token=${token}&callbackURL=${
|
||||
ctx.body.callbackURL || "/"
|
||||
}`;
|
||||
await ctx.context.options.emailVerification.sendVerificationEmail(
|
||||
{
|
||||
user: user,
|
||||
url,
|
||||
token,
|
||||
},
|
||||
ctx.request,
|
||||
);
|
||||
}
|
||||
|
||||
throw new APIError("FORBIDDEN", {
|
||||
message: ERROR_CODES.EMAIL_NOT_VERIFIED,
|
||||
});
|
||||
}
|
||||
|
||||
const account = await ctx.context.adapter.findOne<Account>({
|
||||
model: "account",
|
||||
where: [
|
||||
@@ -360,6 +323,44 @@ export const username = (options?: UsernameOptions) => {
|
||||
message: ERROR_CODES.INVALID_USERNAME_OR_PASSWORD,
|
||||
});
|
||||
}
|
||||
|
||||
if (
|
||||
ctx.context.options?.emailAndPassword?.requireEmailVerification &&
|
||||
!user.emailVerified
|
||||
) {
|
||||
if (
|
||||
!ctx.context.options?.emailVerification?.sendVerificationEmail
|
||||
) {
|
||||
throw new APIError("FORBIDDEN", {
|
||||
message: ERROR_CODES.EMAIL_NOT_VERIFIED,
|
||||
});
|
||||
}
|
||||
|
||||
if (ctx.context.options?.emailVerification?.sendOnSignIn) {
|
||||
const token = await createEmailVerificationToken(
|
||||
ctx.context.secret,
|
||||
user.email,
|
||||
undefined,
|
||||
ctx.context.options.emailVerification?.expiresIn,
|
||||
);
|
||||
const url = `${ctx.context.baseURL}/verify-email?token=${token}&callbackURL=${
|
||||
ctx.body.callbackURL || "/"
|
||||
}`;
|
||||
await ctx.context.options.emailVerification.sendVerificationEmail(
|
||||
{
|
||||
user: user,
|
||||
url,
|
||||
token,
|
||||
},
|
||||
ctx.request,
|
||||
);
|
||||
}
|
||||
|
||||
throw new APIError("FORBIDDEN", {
|
||||
message: ERROR_CODES.EMAIL_NOT_VERIFIED,
|
||||
});
|
||||
}
|
||||
|
||||
const session = await ctx.context.internalAdapter.createSession(
|
||||
user.id,
|
||||
ctx,
|
||||
|
||||
@@ -533,3 +533,44 @@ describe("post normalization flow", async (it) => {
|
||||
expect(session?.user.displayUsername).toBe("Test Username");
|
||||
});
|
||||
});
|
||||
|
||||
describe("username email verification flow (no info leak)", async (it) => {
|
||||
const { client } = await getTestInstance(
|
||||
{
|
||||
emailAndPassword: { enabled: true, requireEmailVerification: true },
|
||||
plugins: [username()],
|
||||
},
|
||||
{
|
||||
clientOptions: {
|
||||
plugins: [usernameClient()],
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
it("returns INVALID_USERNAME_OR_PASSWORD for wrong password even if email is unverified", async () => {
|
||||
await client.signUp.email({
|
||||
email: "unverified-user@example.com",
|
||||
username: "unverified_user",
|
||||
password: "correct-password",
|
||||
name: "Unverified User",
|
||||
});
|
||||
|
||||
const res = await client.signIn.username({
|
||||
username: "unverified_user",
|
||||
password: "wrong-password",
|
||||
});
|
||||
|
||||
expect(res.error?.status).toBe(401);
|
||||
expect(res.error?.code).toBe("INVALID_USERNAME_OR_PASSWORD");
|
||||
});
|
||||
|
||||
it("returns EMAIL_NOT_VERIFIED only after a correct password for an unverified user", async () => {
|
||||
const res = await client.signIn.username({
|
||||
username: "unverified_user",
|
||||
password: "correct-password",
|
||||
});
|
||||
|
||||
expect(res.error?.status).toBe(403);
|
||||
expect(res.error?.code).toBe("EMAIL_NOT_VERIFIED");
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user