diff --git a/apps/login/app/(login)/mfa/set/page.tsx b/apps/login/app/(login)/mfa/set/page.tsx index 0fbd6860a34..647d436fded 100644 --- a/apps/login/app/(login)/mfa/set/page.tsx +++ b/apps/login/app/(login)/mfa/set/page.tsx @@ -20,7 +20,7 @@ export default async function Page({ }: { searchParams: Record; }) { - const { loginName, altPassword, authRequestId, organization, sessionId } = + const { loginName, checkAfter, authRequestId, organization, sessionId } = searchParams; const sessionFactors = sessionId @@ -95,6 +95,7 @@ export default async function Page({ organization={organization} loginSettings={loginSettings} userMethods={sessionFactors.authMethods ?? []} + checkAfter={checkAfter === "true"} > ) : ( No second factors available to setup. diff --git a/apps/login/app/(login)/otp/[method]/set/page.tsx b/apps/login/app/(login)/otp/[method]/set/page.tsx index e6f823a1c4e..779b6a9ebe6 100644 --- a/apps/login/app/(login)/otp/[method]/set/page.tsx +++ b/apps/login/app/(login)/otp/[method]/set/page.tsx @@ -7,11 +7,14 @@ import { server, } from "#/lib/zitadel"; import Alert from "#/ui/Alert"; +import { Button, ButtonVariants } from "#/ui/Button"; import DynamicTheme from "#/ui/DynamicTheme"; +import { Spinner } from "#/ui/Spinner"; import TOTPRegister from "#/ui/TOTPRegister"; import UserAvatar from "#/ui/UserAvatar"; import { getMostRecentCookieWithLoginname } from "#/utils/cookies"; import { RegisterTOTPResponse } from "@zitadel/server"; +import Link from "next/link"; import { ClientError } from "nice-grpc"; export default async function Page({ @@ -21,7 +24,8 @@ export default async function Page({ searchParams: Record; params: Record; }) { - const { loginName, organization, sessionId, authRequestId } = searchParams; + const { loginName, organization, sessionId, authRequestId, checkAfter } = + searchParams; const { method } = params; const branding = await getBrandingSettings(server, organization); @@ -65,6 +69,34 @@ export default async function Page({ }); } + const paramsToContinue = new URLSearchParams({}); + let urlToContinue = "/accounts"; + + if (authRequestId && sessionId) { + if (sessionId) { + paramsToContinue.append("sessionId", sessionId); + } + if (authRequestId) { + paramsToContinue.append("authRequestId", authRequestId); + } + if (organization) { + paramsToContinue.append("organization", organization); + } + urlToContinue = `/login?` + paramsToContinue; + } else if (loginName) { + if (loginName) { + paramsToContinue.append("loginName", loginName); + } + if (authRequestId) { + paramsToContinue.append("authRequestId", authRequestId); + } + if (organization) { + paramsToContinue.append("organization", organization); + } + + urlToContinue = `/signedin?` + paramsToContinue; + } + return (
@@ -107,17 +139,39 @@ export default async function Page({ sessionId={sessionId} authRequestId={authRequestId} organization={organization} + checkAfter={checkAfter === "true"} >
{" "} ) : ( -

- {method === "email" - ? "Code via email was successfully added." - : method === "sms" - ? "Code via SMS was successfully added." - : ""} -

+ <> +

+ {method === "email" + ? "Code via email was successfully added." + : method === "sms" + ? "Code via SMS was successfully added." + : ""} +

+ +
+ + + + +
+ )}
diff --git a/apps/login/ui/ChooseSecondFactorToSetup.tsx b/apps/login/ui/ChooseSecondFactorToSetup.tsx index d17675e86db..d90f7838c4b 100644 --- a/apps/login/ui/ChooseSecondFactorToSetup.tsx +++ b/apps/login/ui/ChooseSecondFactorToSetup.tsx @@ -17,6 +17,7 @@ type Props = { organization?: string; loginSettings: LoginSettings; userMethods: AuthenticationMethodType[]; + checkAfter: boolean; }; export default function ChooseSecondFactorToSetup({ @@ -26,6 +27,7 @@ export default function ChooseSecondFactorToSetup({ organization, loginSettings, userMethods, + checkAfter, }: Props) { const cardClasses = (alreadyAdded: boolean) => clsx( @@ -47,6 +49,9 @@ export default function ChooseSecondFactorToSetup({ if (organization) { params.append("organization", organization); } + if (checkAfter) { + params.append("checkAfter", "true"); + } const TOTP = (alreadyAdded: boolean) => { return ( diff --git a/apps/login/ui/PasswordForm.tsx b/apps/login/ui/PasswordForm.tsx index 450cdc9329b..4e77c5cbe26 100644 --- a/apps/login/ui/PasswordForm.tsx +++ b/apps/login/ui/PasswordForm.tsx @@ -120,6 +120,7 @@ export default function PasswordForm({ } else if (loginSettings?.forceMfa && !resp.authFactors?.length) { const params = new URLSearchParams({ loginName: resp.factors.user.loginName, + checkAfter: "true", // this defines if the check is directly made after the setup }); if (authRequestId) { diff --git a/apps/login/ui/TOTPRegister.tsx b/apps/login/ui/TOTPRegister.tsx index 09ba00a8873..dce7d902678 100644 --- a/apps/login/ui/TOTPRegister.tsx +++ b/apps/login/ui/TOTPRegister.tsx @@ -23,6 +23,7 @@ type Props = { sessionId?: string; authRequestId?: string; organization?: string; + checkAfter?: boolean; }; export default function TOTPRegister({ uri, @@ -31,6 +32,7 @@ export default function TOTPRegister({ sessionId, authRequestId, organization, + checkAfter, }: Props) { const [error, setError] = useState(""); const [loading, setLoading] = useState(false); @@ -48,22 +50,13 @@ export default function TOTPRegister({ return verifyTOTP(values.code, loginName, organization) .then((response) => { setLoading(false); - if (authRequestId && sessionId) { - const params = new URLSearchParams({ - sessionId: sessionId, - authRequest: authRequestId, - }); + // if attribute is set, validate MFA after it is setup, otherwise proceed as usual (when mfa is enforced to login) + if (checkAfter) { + const params = new URLSearchParams({}); - if (organization) { - params.append("organization", organization); + if (loginName) { + params.append("loginName", loginName); } - - return router.push(`/login?` + params); - } else if (loginName) { - const params = new URLSearchParams({ - loginName, - }); - if (authRequestId) { params.append("authRequestId", authRequestId); } @@ -71,7 +64,33 @@ export default function TOTPRegister({ params.append("organization", organization); } - return router.push(`/signedin?` + params); + return router.push(`/otp/time-based?` + params); + } else { + if (authRequestId && sessionId) { + const params = new URLSearchParams({ + sessionId: sessionId, + authRequest: authRequestId, + }); + + if (organization) { + params.append("organization", organization); + } + + return router.push(`/login?` + params); + } else if (loginName) { + const params = new URLSearchParams({ + loginName, + }); + + if (authRequestId) { + params.append("authRequestId", authRequestId); + } + if (organization) { + params.append("organization", organization); + } + + return router.push(`/signedin?` + params); + } } }) .catch((e) => {