diff --git a/packages/better-auth/src/api/routes/email-verification.ts b/packages/better-auth/src/api/routes/email-verification.ts index ee6e5d63e7..eb1fd945fd 100644 --- a/packages/better-auth/src/api/routes/email-verification.ts +++ b/packages/better-auth/src/api/routes/email-verification.ts @@ -5,6 +5,7 @@ import { createAuthEndpoint } from "../call"; import { APIError } from "better-call"; import { getSessionFromCtx } from "./session"; import { setSessionCookie } from "../../cookies"; +import type { GenericEndpointContext, User } from "../../types"; export async function createEmailVerificationToken( secret: string, @@ -32,6 +33,36 @@ export async function createEmailVerificationToken( return token; } +/** + * A function to send a verification email to the user + */ +export async function sendVerificationEmailFn( + ctx: GenericEndpointContext, + user: User, +) { + if (!ctx.context.options.emailVerification?.sendVerificationEmail) { + ctx.context.logger.error("Verification email isn't enabled."); + throw new APIError("BAD_REQUEST", { + message: "Verification email isn't enabled", + }); + } + const token = await createEmailVerificationToken( + ctx.context.secret, + user.email, + ); + const url = `${ctx.context.baseURL}/verify-email?token=${token}&callbackURL=${ + ctx.body.callbackURL || ctx.query?.currentURL || "/" + }`; + await ctx.context.options.emailVerification.sendVerificationEmail( + { + user: user, + url, + token, + }, + ctx.request, + ); +} + export const sendVerificationEmail = createAuthEndpoint( "/send-verification-email", { @@ -115,20 +146,7 @@ export const sendVerificationEmail = createAuthEndpoint( message: "User not found", }); } - const token = await createEmailVerificationToken(ctx.context.secret, email); - const url = `${ - ctx.context.baseURL - }/verify-email?token=${token}&callbackURL=${ - ctx.body.callbackURL || ctx.query?.currentURL || "/" - }`; - await ctx.context.options.emailVerification.sendVerificationEmail( - { - user: user.user, - url, - token, - }, - ctx.request, - ); + await sendVerificationEmailFn(ctx, user.user); return ctx.json({ status: true, }); diff --git a/packages/better-auth/src/plugins/username/index.ts b/packages/better-auth/src/plugins/username/index.ts index 82e0d6cb20..3cc67624a8 100644 --- a/packages/better-auth/src/plugins/username/index.ts +++ b/packages/better-auth/src/plugins/username/index.ts @@ -4,6 +4,7 @@ import type { BetterAuthPlugin } from "../../types/plugins"; import { APIError } from "better-call"; import type { Account, User } from "../../db/schema"; import { setSessionCookie } from "../../cookies"; +import { sendVerificationEmailFn } from "../../api"; export const username = () => { return { @@ -70,6 +71,17 @@ export const username = () => { message: "Invalid username or password", }); } + + if ( + !user.emailVerified && + ctx.context.options.emailAndPassword?.requireEmailVerification + ) { + await sendVerificationEmailFn(ctx, user); + throw new APIError("UNAUTHORIZED", { + message: "Email not verified", + }); + } + const account = await ctx.context.adapter.findOne({ model: "account", where: [