diff --git a/apps/login/src/app/(login)/otp/[method]/page.tsx b/apps/login/src/app/(login)/otp/[method]/page.tsx index 64b7c9ed2e..1755561238 100644 --- a/apps/login/src/app/(login)/otp/[method]/page.tsx +++ b/apps/login/src/app/(login)/otp/[method]/page.tsx @@ -2,8 +2,13 @@ import { Alert } from "@/components/alert"; import { DynamicTheme } from "@/components/dynamic-theme"; import { LoginOTP } from "@/components/login-otp"; import { UserAvatar } from "@/components/user-avatar"; +import { getSessionCookieById } from "@/lib/cookies"; import { loadMostRecentSession } from "@/lib/session"; -import { getBrandingSettings, getLoginSettings } from "@/lib/zitadel"; +import { + getBrandingSettings, + getLoginSettings, + getSession, +} from "@/lib/zitadel"; import { getLocale, getTranslations } from "next-intl/server"; import { headers } from "next/headers"; @@ -17,15 +22,33 @@ export default async function Page(props: { const t = await getTranslations({ locale, namespace: "otp" }); const tError = await getTranslations({ locale, namespace: "error" }); - const { loginName, authRequestId, sessionId, organization, code, submit } = - searchParams; + const { + loginName, // send from password page + userId, // send from email link + authRequestId, + sessionId, + organization, + code, + submit, + } = searchParams; const { method } = params; - const session = await loadMostRecentSession({ - loginName, - organization, - }); + const session = sessionId + ? await loadSessionById(sessionId, organization) + : await loadMostRecentSession({ loginName, organization }); + + async function loadSessionById(sessionId: string, organization?: string) { + const recent = await getSessionCookieById({ sessionId, organization }); + return getSession({ + sessionId: recent.id, + sessionToken: recent.token, + }).then((response) => { + if (response?.session) { + return response.session; + } + }); + } // email links do not come with organization, thus we need to use the session's organization const branding = await getBrandingSettings( @@ -67,12 +90,14 @@ export default async function Page(props: { > )} - {method && ( + {method && session && ( { setLoading(true); // Wait for 2 seconds to avoid eventual consistency issues with an OTP code being verified in the /login endpoint - await new Promise((resolve) => setTimeout(resolve, 4000)); + await new Promise((resolve) => setTimeout(resolve, 2000)); if (response) { const url =