diff --git a/apps/login/src/lib/server/loginname.ts b/apps/login/src/lib/server/loginname.ts index b35cbe0d664..5831d3eb21f 100644 --- a/apps/login/src/lib/server/loginname.ts +++ b/apps/login/src/lib/server/loginname.ts @@ -1,5 +1,7 @@ "use server"; +import { PasskeysType } from "@zitadel/proto/zitadel/settings/v2/login_settings_pb"; +import { AuthenticationMethodType } from "@zitadel/proto/zitadel/user/v2/user_service_pb"; import { headers } from "next/headers"; import { redirect } from "next/navigation"; import { createSessionForUserIdAndUpdateCookie } from "../../utils/session"; @@ -24,6 +26,8 @@ export async function sendLoginname(command: SendLoginnameCommand) { organizationId: command.organization, }); + const loginSettings = await getLoginSettings(command.organization); + if (users.details?.totalResult == BigInt(1) && users.result[0].userId) { const userId = users.result[0].userId; const session = await createSessionForUserIdAndUpdateCookie( @@ -41,14 +45,102 @@ export async function sendLoginname(command: SendLoginnameCommand) { session.factors?.user?.id, ); - return { - authMethodTypes: methods.authMethodTypes, - sessionId: session.id, - factors: session.factors, - }; + if (!methods.authMethodTypes || !methods.authMethodTypes.length) { + throw Error( + "User has no available authentication methods. Contact your administrator to setup authentication for the requested user.", + ); + } + + if (methods.authMethodTypes.length == 1) { + const method = methods.authMethodTypes[0]; + switch (method) { + case AuthenticationMethodType.PASSWORD: // user has only password as auth method + const paramsPassword: any = { + loginName: session.factors?.user?.loginName, + }; + + // TODO: does this have to be checked in loginSettings.allowDomainDiscovery + + if (command.organization || session.factors?.user?.organizationId) { + paramsPassword.organization = + command.organization ?? session.factors?.user?.organizationId; + } + + if ( + loginSettings?.passkeysType && + loginSettings?.passkeysType === PasskeysType.ALLOWED + ) { + paramsPassword.promptPasswordless = `true`; + } + + if (command.authRequestId) { + paramsPassword.authRequestId = command.authRequestId; + } + + return redirect("/password?" + new URLSearchParams(paramsPassword)); + case AuthenticationMethodType.PASSKEY: // AuthenticationMethodType.AUTHENTICATION_METHOD_TYPE_PASSKEY + const paramsPasskey: any = { loginName: command.loginName }; + if (command.authRequestId) { + paramsPasskey.authRequestId = command.authRequestId; + } + + if (command.organization || session.factors?.user?.organizationId) { + paramsPasskey.organization = + command.organization ?? session.factors?.user?.organizationId; + } + + return redirect( + "/passkey/login?" + new URLSearchParams(paramsPasskey), + ); + } + } else { + // prefer passkey in favor of other methods + if (methods.authMethodTypes.includes(AuthenticationMethodType.PASSKEY)) { + const passkeyParams: any = { + loginName: command.loginName, + altPassword: `${methods.authMethodTypes.includes(1)}`, // show alternative password option + }; + + if (command.authRequestId) { + passkeyParams.authRequestId = command.authRequestId; + } + + if (command.organization || session.factors?.user?.organizationId) { + passkeyParams.organization = + command.organization ?? session.factors?.user?.organizationId; + } + + return redirect("/passkey/login?" + new URLSearchParams(passkeyParams)); + } else if ( + methods.authMethodTypes.includes(AuthenticationMethodType.IDP) + ) { + // TODO: redirect user to idp + } else if ( + methods.authMethodTypes.includes(AuthenticationMethodType.PASSWORD) + ) { + // user has no passkey setup and login settings allow passkeys + const paramsPasswordDefault: any = { loginName: command.loginName }; + + if (loginSettings?.passkeysType === 1) { + paramsPasswordDefault.promptPasswordless = `true`; // PasskeysType.PASSKEYS_TYPE_ALLOWED, + } + + if (command.authRequestId) { + paramsPasswordDefault.authRequestId = command.authRequestId; + } + + if (command.organization || session.factors?.user?.organizationId) { + paramsPasswordDefault.organization = + command.organization ?? session.factors?.user?.organizationId; + } + + return redirect( + "/password?" + new URLSearchParams(paramsPasswordDefault), + ); + } + } } - const loginSettings = await getLoginSettings(command.organization); // TODO: check if allowDomainDiscovery has to be allowed too, to redirect to the register page // user not found, check if register is enabled on organization diff --git a/apps/login/src/ui/UsernameForm.tsx b/apps/login/src/ui/UsernameForm.tsx index 7ab4ec82e16..aed25fb23fc 100644 --- a/apps/login/src/ui/UsernameForm.tsx +++ b/apps/login/src/ui/UsernameForm.tsx @@ -1,11 +1,7 @@ "use client"; import { sendLoginname } from "@/lib/server/loginname"; -import { - LoginSettings, - PasskeysType, -} from "@zitadel/proto/zitadel/settings/v2/login_settings_pb"; -import { AuthenticationMethodType } from "@zitadel/proto/zitadel/user/v2/user_service_pb"; +import { LoginSettings } from "@zitadel/proto/zitadel/settings/v2/login_settings_pb"; import { useRouter } from "next/navigation"; import { ReactNode, useEffect, useState } from "react"; import { useForm } from "react-hook-form"; @@ -71,123 +67,6 @@ export default function UsernameForm({ organization?: string, ) { const response = await submitLoginName(values, organization); - - if (!response) { - return; - } - - if (response.authMethodTypes && response.authMethodTypes.length === 0) { - setError( - "User has no available authentication methods. Contact your administrator to setup authentication for the requested user.", - ); - return; - } - - if (response.authMethodTypes.length == 1) { - const method = response.authMethodTypes[0]; - switch (method) { - case AuthenticationMethodType.PASSWORD: // user has only password as auth method - const paramsPassword: any = { - loginName: response.factors?.user?.loginName, - }; - - // TODO: does this have to be checked in loginSettings.allowDomainDiscovery - - if (organization || response.factors?.user?.organizationId) { - paramsPassword.organization = - organization ?? response.factors?.user?.organizationId; - } - - if ( - loginSettings?.passkeysType && - loginSettings?.passkeysType === PasskeysType.ALLOWED - ) { - paramsPassword.promptPasswordless = `true`; - } - - if (authRequestId) { - paramsPassword.authRequestId = authRequestId; - } - - return router.push( - "/password?" + new URLSearchParams(paramsPassword), - ); - case AuthenticationMethodType.PASSKEY: // AuthenticationMethodType.AUTHENTICATION_METHOD_TYPE_PASSKEY - const paramsPasskey: any = { loginName: values.loginName }; - if (authRequestId) { - paramsPasskey.authRequestId = authRequestId; - } - - if (organization || response.factors?.user?.organizationId) { - paramsPasskey.organization = - organization ?? response.factors?.user?.organizationId; - } - - return router.push( - "/passkey/login?" + new URLSearchParams(paramsPasskey), - ); - default: - const paramsPasskeyDefault: any = { loginName: values.loginName }; - - if (loginSettings?.passkeysType === 1) { - paramsPasskeyDefault.promptPasswordless = `true`; // PasskeysType.PASSKEYS_TYPE_ALLOWED, - } - - if (authRequestId) { - paramsPasskeyDefault.authRequestId = authRequestId; - } - - if (organization || response.factors?.user?.organizationId) { - paramsPasskeyDefault.organization = - organization ?? response.factors?.user?.organizationId; - } - - return router.push( - "/password?" + new URLSearchParams(paramsPasskeyDefault), - ); - } - } else { - // prefer passkey in favor of other methods - if (response.authMethodTypes.includes(2)) { - const passkeyParams: any = { - loginName: values.loginName, - altPassword: `${response.authMethodTypes.includes(1)}`, // show alternative password option - }; - - if (authRequestId) { - passkeyParams.authRequestId = authRequestId; - } - - if (organization || response.factors?.user?.organizationId) { - passkeyParams.organization = - organization ?? response.factors?.user?.organizationId; - } - - return router.push( - "/passkey/login?" + new URLSearchParams(passkeyParams), - ); - } else { - // user has no passkey setup and login settings allow passkeys - const paramsPasswordDefault: any = { loginName: values.loginName }; - - if (loginSettings?.passkeysType === 1) { - paramsPasswordDefault.promptPasswordless = `true`; // PasskeysType.PASSKEYS_TYPE_ALLOWED, - } - - if (authRequestId) { - paramsPasswordDefault.authRequestId = authRequestId; - } - - if (organization || response.factors?.user?.organizationId) { - paramsPasswordDefault.organization = - organization ?? response.factors?.user?.organizationId; - } - - return router.push( - "/password?" + new URLSearchParams(paramsPasswordDefault), - ); - } - } } useEffect(() => {