From eea139eca608b4f9d502eb8fb9f06308bc65867e Mon Sep 17 00:00:00 2001 From: Max Peintner Date: Fri, 23 May 2025 10:55:53 +0200 Subject: [PATCH] recheck for valid user verification on /authenticator/set remove check on the /verify page itself --- .../app/(login)/authenticator/set/page.tsx | 37 +++++++++++++++++-- apps/login/src/app/(login)/verify/page.tsx | 5 +-- .../src/components/verify-redirect-button.tsx | 14 ++++++- apps/login/src/lib/server/verify.ts | 6 ++- 4 files changed, 52 insertions(+), 10 deletions(-) diff --git a/apps/login/src/app/(login)/authenticator/set/page.tsx b/apps/login/src/app/(login)/authenticator/set/page.tsx index 3e1b49eed0..63704b87eb 100644 --- a/apps/login/src/app/(login)/authenticator/set/page.tsx +++ b/apps/login/src/app/(login)/authenticator/set/page.tsx @@ -7,6 +7,7 @@ import { UserAvatar } from "@/components/user-avatar"; import { getSessionCookieById } from "@/lib/cookies"; import { getServiceUrlFromHeaders } from "@/lib/service-url"; import { loadMostRecentSession } from "@/lib/session"; +import { checkUserVerification } from "@/lib/verify-helper"; import { getActiveIdentityProviders, getBrandingSettings, @@ -18,6 +19,7 @@ import { import { Session } from "@zitadel/proto/zitadel/session/v2/session_pb"; import { getLocale, getTranslations } from "next-intl/server"; import { headers } from "next/headers"; +import { redirect } from "next/navigation"; export default async function Page(props: { searchParams: Promise>; @@ -92,20 +94,49 @@ export default async function Page(props: { }); } - if (!sessionWithData) { + if ( + !sessionWithData || + !sessionWithData.factors || + !sessionWithData.factors.user + ) { return {tError("unknownContext")}; } const branding = await getBrandingSettings({ serviceUrl, - organization: sessionWithData.factors?.user?.organizationId, + organization: sessionWithData.factors.user?.organizationId, }); const loginSettings = await getLoginSettings({ serviceUrl, - organization: sessionWithData.factors?.user?.organizationId, + organization: sessionWithData.factors.user?.organizationId, }); + // check if user was verified recently + const isUserVerified = await checkUserVerification( + sessionWithData.factors.user?.id, + ); + + if (!isUserVerified) { + const params = new URLSearchParams({ + loginName: sessionWithData.factors.user.loginName as string, + send: "true", // set this to true to request a new code immediately + }); + + if (requestId) { + params.append("requestId", requestId); + } + + if (organization || sessionWithData.factors.user.organizationId) { + params.append( + "organization", + organization ?? (sessionWithData.factors.user.organizationId as string), + ); + } + + redirect(`/verify?` + params); + } + const identityProviders = await getActiveIdentityProviders({ serviceUrl, orgId: sessionWithData.factors?.user?.organizationId, diff --git a/apps/login/src/app/(login)/verify/page.tsx b/apps/login/src/app/(login)/verify/page.tsx index fcbc4fd34a..c9136b4669 100644 --- a/apps/login/src/app/(login)/verify/page.tsx +++ b/apps/login/src/app/(login)/verify/page.tsx @@ -6,7 +6,6 @@ import { VerifyRedirectButton } from "@/components/verify-redirect-button"; import { sendEmailCode } from "@/lib/server/verify"; import { getServiceUrlFromHeaders } from "@/lib/service-url"; import { loadMostRecentSession } from "@/lib/session"; -import { checkUserVerification } from "@/lib/verify-helper"; import { getBrandingSettings, getUserByID, @@ -112,8 +111,6 @@ export default async function Page(props: { searchParams: Promise }) { } } - const hasValidUserVerificationCheck = await checkUserVerification(id); - const params = new URLSearchParams({ userId: userId, initial: "true", // defines that a code is not required and is therefore not shown in the UI @@ -172,7 +169,7 @@ export default async function Page(props: { searchParams: Promise }) { )} {/* show a button to setup auth method for the user otherwise show the UI for reverifying */} - {human?.email?.isVerified && hasValidUserVerificationCheck ? ( + {human?.email?.isVerified ? ( // show page for already verified users (""); const [loading, setLoading] = useState(false); + const router = useRouter(); async function submitAndContinue(): Promise { setLoading(true); @@ -50,7 +52,7 @@ export function VerifyRedirectButton({ } as SendVerificationRedirectWithoutCheckCommand; } - await sendVerificationRedirectWithoutCheck(command) + const response = await sendVerificationRedirectWithoutCheck(command) .catch(() => { setError("Could not verify"); return; @@ -58,6 +60,16 @@ export function VerifyRedirectButton({ .finally(() => { setLoading(false); }); + + if (response && "error" in response && response.error) { + setError(response.error); + return; + } + + if (response && "redirect" in response && response.redirect) { + router.push(response.redirect); + return true; + } } return ( diff --git a/apps/login/src/lib/server/verify.ts b/apps/login/src/lib/server/verify.ts index 0ab4c5465d..34176a45e6 100644 --- a/apps/login/src/lib/server/verify.ts +++ b/apps/login/src/lib/server/verify.ts @@ -71,14 +71,16 @@ export async function sendVerification(command: VerifyUserByEmailCommand) { serviceUrl, userId: command.userId, verificationCode: command.code, - }).catch(() => { + }).catch((error) => { + console.warn(error); return { error: "Could not verify invite" }; }) : await verifyEmail({ serviceUrl, userId: command.userId, verificationCode: command.code, - }).catch(() => { + }).catch((error) => { + console.warn(error); return { error: "Could not verify email" }; });