mirror of
https://github.com/better-auth/better-auth.git
synced 2026-05-24 08:01:56 -05:00
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:
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user