diff --git a/apps/login/locales/de.json b/apps/login/locales/de.json index 5e8756c89b..db46321b05 100644 --- a/apps/login/locales/de.json +++ b/apps/login/locales/de.json @@ -71,7 +71,8 @@ }, "set": { "title": "2-Faktor einrichten", - "description": "Wählen Sie einen der folgenden zweiten Faktoren." + "description": "Wählen Sie einen der folgenden zweiten Faktoren.", + "skip": "Überspringen" } }, "otp": { diff --git a/apps/login/locales/en.json b/apps/login/locales/en.json index 3101f222d5..36776ccbd9 100644 --- a/apps/login/locales/en.json +++ b/apps/login/locales/en.json @@ -71,7 +71,8 @@ }, "set": { "title": "Set up 2-Factor", - "description": "Choose one of the following second factors." + "description": "Choose one of the following second factors.", + "skip": "Skip" } }, "otp": { diff --git a/apps/login/locales/es.json b/apps/login/locales/es.json index 5a9b6f6324..4eba3a9696 100644 --- a/apps/login/locales/es.json +++ b/apps/login/locales/es.json @@ -71,7 +71,8 @@ }, "set": { "title": "Configurar autenticación de 2 factores", - "description": "Elige uno de los siguientes factores secundarios." + "description": "Elige uno de los siguientes factores secundarios.", + "skip": "Omitir" } }, "otp": { diff --git a/apps/login/locales/it.json b/apps/login/locales/it.json index 1423c43cfe..d0969c86b3 100644 --- a/apps/login/locales/it.json +++ b/apps/login/locales/it.json @@ -71,7 +71,8 @@ }, "set": { "title": "Configura l'autenticazione a 2 fattori", - "description": "Scegli uno dei seguenti secondi fattori." + "description": "Scegli uno dei seguenti secondi fattori.", + "skip": "Salta" } }, "otp": { diff --git a/apps/login/locales/zh.json b/apps/login/locales/zh.json index acd03cc5b6..9c87a53a65 100644 --- a/apps/login/locales/zh.json +++ b/apps/login/locales/zh.json @@ -71,7 +71,8 @@ }, "set": { "title": "设置双因素认证", - "description": "选择以下的一个第二因素。" + "description": "选择以下的一个第二因素。", + "skip": "跳过" } }, "otp": { diff --git a/apps/login/src/app/(login)/mfa/set/page.tsx b/apps/login/src/app/(login)/mfa/set/page.tsx index a885a36c7a..a8f16f23f2 100644 --- a/apps/login/src/app/(login)/mfa/set/page.tsx +++ b/apps/login/src/app/(login)/mfa/set/page.tsx @@ -161,6 +161,12 @@ export default async function Page(props: { > )} + {force !== "true" && ( +
+

{t("set.skip")}

+
+ )} +
diff --git a/apps/login/src/lib/server/password.ts b/apps/login/src/lib/server/password.ts index 98c34a3de6..6fd3f67bcd 100644 --- a/apps/login/src/lib/server/password.ts +++ b/apps/login/src/lib/server/password.ts @@ -16,7 +16,7 @@ import { setPassword, setUserPassword, } from "@/lib/zitadel"; -import { create } from "@zitadel/client"; +import { ConnectError, create } from "@zitadel/client"; import { createServerTransport } from "@zitadel/client/node"; import { createUserServiceClient } from "@zitadel/client/v2"; import { @@ -267,7 +267,8 @@ export async function sendPassword(command: UpdateSessionCommand) { return { error: "Could not verify password!" }; } - const mfaFactorCheck = checkMFAFactors( + const mfaFactorCheck = await checkMFAFactors( + serviceUrl, session, loginSettings, authMethods, @@ -433,7 +434,7 @@ export async function checkSessionAndSetPassword({ }, {}, ) - .catch((error) => { + .catch((error: ConnectError) => { console.log(error); if (error.code === 7) { return { error: "Session is not valid." }; diff --git a/apps/login/src/lib/server/verify.ts b/apps/login/src/lib/server/verify.ts index 38bddb9428..4de697e772 100644 --- a/apps/login/src/lib/server/verify.ts +++ b/apps/login/src/lib/server/verify.ts @@ -203,7 +203,8 @@ export async function sendVerification(command: VerifyUserByEmailCommand) { } // redirect to mfa factor if user has one, or redirect to set one up - const mfaFactorCheck = checkMFAFactors( + const mfaFactorCheck = await checkMFAFactors( + serviceUrl, session, loginSettings, authMethodResponse.authMethodTypes, @@ -407,12 +408,12 @@ export async function sendVerificationRedirectWithoutCheck( const loginSettings = await getLoginSettings({ serviceUrl, - organization: user.details?.resourceOwner, }); // redirect to mfa factor if user has one, or redirect to set one up - const mfaFactorCheck = checkMFAFactors( + const mfaFactorCheck = await checkMFAFactors( + serviceUrl, session, loginSettings, authMethodResponse.authMethodTypes, diff --git a/apps/login/src/lib/verify-helper.ts b/apps/login/src/lib/verify-helper.ts index e8afef6890..fcc46e175c 100644 --- a/apps/login/src/lib/verify-helper.ts +++ b/apps/login/src/lib/verify-helper.ts @@ -5,6 +5,7 @@ import { PasswordExpirySettings } from "@zitadel/proto/zitadel/settings/v2/passw import { HumanUser } from "@zitadel/proto/zitadel/user/v2/user_pb"; import { AuthenticationMethodType } from "@zitadel/proto/zitadel/user/v2/user_service_pb"; import moment from "moment"; +import { getUserByID } from "./zitadel"; export function checkPasswordChangeRequired( expirySettings: PasswordExpirySettings | undefined, @@ -100,7 +101,8 @@ export function checkEmailVerification( } } -export function checkMFAFactors( +export async function checkMFAFactors( + serviceUrl: string, session: Session, loginSettings: LoginSettings | undefined, authMethods: AuthenticationMethodType[], @@ -188,31 +190,42 @@ export function checkMFAFactors( ); } + // TODO: provide a way to setup passkeys on mfa page? + return { redirect: `/mfa/set?` + params }; + } else if ( + loginSettings?.mfaInitSkipLifetime && + (loginSettings.mfaInitSkipLifetime.nanos > 0 || + loginSettings.mfaInitSkipLifetime.seconds > 0) && + !availableMultiFactors.length && + session?.factors?.user?.id + ) { + const user = await getUserByID({ + serviceUrl, + userId: session.factors?.user?.id, + }); + if ( + user.user?.type?.case === "human" && + user.user?.type?.value.mfaInitSkipped + ) { + } + const params = new URLSearchParams({ + loginName: session.factors?.user?.loginName as string, + force: "false", // this defines if the mfa is not forced in the settings and can be skipped + checkAfter: "true", // this defines if the check is directly made after the setup + }); + + if (requestId) { + params.append("requestId", requestId); + } + + if (organization || session.factors?.user?.organizationId) { + params.append( + "organization", + organization ?? (session.factors?.user?.organizationId as string), + ); + } + // TODO: provide a way to setup passkeys on mfa page? return { redirect: `/mfa/set?` + params }; } - - // TODO: implement passkey setup - - // else if ( - // submitted.factors && - // !submitted.factors.webAuthN && // if session was not verified with a passkey - // promptPasswordless && // if explicitly prompted due policy - // !isAlternative // escaped if password was used as an alternative method - // ) { - // const params = new URLSearchParams({ - // loginName: submitted.factors.user.loginName, - // prompt: "true", - // }); - - // if (requestId) { - // params.append("requestId", requestId); - // } - - // if (organization) { - // params.append("organization", organization); - // } - - // return router.push(`/passkey/set?` + params); - // } }