refactor: replace nested conditionals with switch in email verification

Refactored the email verification handler to use a switch statement on requestType
for better clarity, separating change-email-confirmation, change-email-verification,
and legacy flow cases. This improves readability without changing behavior.

Co-authored-by: taesu <taesu@better-auth.com>
This commit is contained in:
Cursor Agent
2026-01-15 17:29:41 +00:00
parent 2628eba29b
commit 504a088ee2

View File

@@ -309,152 +309,165 @@ export const verifyEmail = createAuthEndpoint(
return redirectOnError(BASE_ERROR_CODES.USER_NOT_FOUND);
}
if (parsed.updateTo) {
let session = await getSessionFromCtx(ctx);
const session = await getSessionFromCtx(ctx);
if (session && session.user.email !== parsed.email) {
return redirectOnError(BASE_ERROR_CODES.INVALID_USER);
}
if (parsed.requestType === "change-email-confirmation") {
const newToken = await createEmailVerificationToken(
ctx.context.secret,
parsed.email,
parsed.updateTo,
ctx.context.options.emailVerification?.expiresIn,
{
requestType: "change-email-verification",
},
);
const updateCallbackURL = ctx.query.callbackURL
? encodeURIComponent(ctx.query.callbackURL)
: encodeURIComponent("/");
const url = `${ctx.context.baseURL}/verify-email?token=${newToken}&callbackURL=${updateCallbackURL}`;
if (ctx.context.options.emailVerification?.sendVerificationEmail) {
await ctx.context.runInBackgroundOrAwait(
ctx.context.options.emailVerification.sendVerificationEmail(
{
user: {
...user.user,
email: parsed.updateTo,
switch (parsed.requestType) {
/**
* User clicks confirmation -> sends verification to new email
*/
case "change-email-confirmation": {
const newToken = await createEmailVerificationToken(
ctx.context.secret,
parsed.email,
parsed.updateTo,
ctx.context.options.emailVerification?.expiresIn,
{ requestType: "change-email-verification" },
);
const updateCallbackURL = ctx.query.callbackURL
? encodeURIComponent(ctx.query.callbackURL)
: encodeURIComponent("/");
const url = `${ctx.context.baseURL}/verify-email?token=${newToken}&callbackURL=${updateCallbackURL}`;
if (ctx.context.options.emailVerification?.sendVerificationEmail) {
await ctx.context.runInBackgroundOrAwait(
ctx.context.options.emailVerification.sendVerificationEmail(
{
user: { ...user.user, email: parsed.updateTo },
url,
token: newToken,
},
url,
token: newToken,
},
ctx.request,
),
);
}
if (ctx.query.callbackURL) {
throw ctx.redirect(ctx.query.callbackURL);
}
return ctx.json({ status: true });
}
/**
* User clicks verification -> updates email
*/
case "change-email-verification": {
let activeSession = session;
if (!activeSession) {
const newSession = await ctx.context.internalAdapter.createSession(
user.user.id,
);
if (!newSession) {
throw APIError.from(
"INTERNAL_SERVER_ERROR",
BASE_ERROR_CODES.FAILED_TO_CREATE_SESSION,
);
}
activeSession = {
session: newSession,
user: user.user,
};
}
if (ctx.context.options.emailVerification?.onEmailVerification) {
await ctx.context.options.emailVerification.onEmailVerification(
user.user,
ctx.request,
),
);
}
if (ctx.query.callbackURL) {
throw ctx.redirect(ctx.query.callbackURL);
}
return ctx.json({
status: true,
});
}
if (!session) {
const newSession = await ctx.context.internalAdapter.createSession(
user.user.id,
);
if (!newSession) {
throw APIError.from(
"INTERNAL_SERVER_ERROR",
BASE_ERROR_CODES.FAILED_TO_CREATE_SESSION,
);
}
session = {
session: newSession,
user: user.user,
};
}
if (parsed.requestType === "change-email-verification") {
if (ctx.context.options.emailVerification?.onEmailVerification) {
await ctx.context.options.emailVerification.onEmailVerification(
user.user,
ctx.request,
);
}
const updatedUser = await ctx.context.internalAdapter.updateUserByEmail(
parsed.email,
{
email: parsed.updateTo,
emailVerified: true,
},
);
if (ctx.context.options.emailVerification?.afterEmailVerification) {
await ctx.context.options.emailVerification.afterEmailVerification(
updatedUser,
ctx.request,
);
}
await setSessionCookie(ctx, {
session: session.session,
user: {
...session.user,
email: parsed.updateTo,
emailVerified: true,
},
});
if (ctx.query.callbackURL) {
throw ctx.redirect(ctx.query.callbackURL);
}
return ctx.json({
status: true,
user: updatedUser,
});
}
const updatedUser = await ctx.context.internalAdapter.updateUserByEmail(
parsed.email,
{
email: parsed.updateTo,
emailVerified: false,
},
);
const newToken = await createEmailVerificationToken(
ctx.context.secret,
parsed.updateTo,
);
//send verification email to the new email
const updateCallbackURL = ctx.query.callbackURL
? encodeURIComponent(ctx.query.callbackURL)
: encodeURIComponent("/");
if (ctx.context.options.emailVerification?.sendVerificationEmail) {
await ctx.context.runInBackgroundOrAwait(
ctx.context.options.emailVerification.sendVerificationEmail(
{
user: updatedUser,
url: `${ctx.context.baseURL}/verify-email?token=${newToken}&callbackURL=${updateCallbackURL}`,
token: newToken,
);
}
const updatedUser =
await ctx.context.internalAdapter.updateUserByEmail(parsed.email, {
email: parsed.updateTo,
emailVerified: true,
});
if (ctx.context.options.emailVerification?.afterEmailVerification) {
await ctx.context.options.emailVerification.afterEmailVerification(
updatedUser,
ctx.request,
);
}
await setSessionCookie(ctx, {
session: activeSession.session,
user: {
...activeSession.user,
email: parsed.updateTo,
emailVerified: true,
},
ctx.request,
),
);
});
if (ctx.query.callbackURL) {
throw ctx.redirect(ctx.query.callbackURL);
}
return ctx.json({ status: true, user: updatedUser });
}
/**
* Legacy flow
*
* - skips two-step verification
* - updates email immediately
*/
default: {
let activeSession = session;
if (!activeSession) {
const newSession = await ctx.context.internalAdapter.createSession(
user.user.id,
);
if (!newSession) {
throw APIError.from(
"INTERNAL_SERVER_ERROR",
BASE_ERROR_CODES.FAILED_TO_CREATE_SESSION,
);
}
activeSession = {
session: newSession,
user: user.user,
};
}
const updatedUser =
await ctx.context.internalAdapter.updateUserByEmail(parsed.email, {
email: parsed.updateTo,
emailVerified: false,
});
const newToken = await createEmailVerificationToken(
ctx.context.secret,
parsed.updateTo,
);
const updateCallbackURL = ctx.query.callbackURL
? encodeURIComponent(ctx.query.callbackURL)
: encodeURIComponent("/");
if (ctx.context.options.emailVerification?.sendVerificationEmail) {
await ctx.context.runInBackgroundOrAwait(
ctx.context.options.emailVerification.sendVerificationEmail(
{
user: updatedUser,
url: `${ctx.context.baseURL}/verify-email?token=${newToken}&callbackURL=${updateCallbackURL}`,
token: newToken,
},
ctx.request,
),
);
}
await setSessionCookie(ctx, {
session: activeSession.session,
user: {
...activeSession.user,
email: parsed.updateTo,
emailVerified: false,
},
});
if (ctx.query.callbackURL) {
throw ctx.redirect(ctx.query.callbackURL);
}
return ctx.json({
status: true,
user: {
id: updatedUser.id,
email: updatedUser.email,
name: updatedUser.name,
image: updatedUser.image,
emailVerified: updatedUser.emailVerified,
createdAt: updatedUser.createdAt,
updatedAt: updatedUser.updatedAt,
},
});
}
}
await setSessionCookie(ctx, {
session: session.session,
user: {
...session.user,
email: parsed.updateTo,
emailVerified: false,
},
});
if (ctx.query.callbackURL) {
throw ctx.redirect(ctx.query.callbackURL);
}
return ctx.json({
status: true,
user: {
id: updatedUser.id,
email: updatedUser.email,
name: updatedUser.name,
image: updatedUser.image,
emailVerified: updatedUser.emailVerified,
createdAt: updatedUser.createdAt,
updatedAt: updatedUser.updatedAt,
},
});
}
if (user.user.emailVerified) {
if (ctx.query.callbackURL) {