diff --git a/apps/login/src/app/(login)/idp/[provider]/failure/page.tsx b/apps/login/src/app/(login)/idp/[provider]/failure/page.tsx index a3cc0ee8839..ced396d44f2 100644 --- a/apps/login/src/app/(login)/idp/[provider]/failure/page.tsx +++ b/apps/login/src/app/(login)/idp/[provider]/failure/page.tsx @@ -1,17 +1,17 @@ +import { Alert, AlertType } from "@/components/alert"; +import { ChooseAuthenticatorToLogin } from "@/components/choose-authenticator-to-login"; import { DynamicTheme } from "@/components/dynamic-theme"; -import { getBrandingSettings } from "@/lib/zitadel"; -import { IdentityProviderType } from "@zitadel/proto/zitadel/settings/v2/login_settings_pb"; +import { UserAvatar } from "@/components/user-avatar"; +import { + getBrandingSettings, + getLoginSettings, + getUserByID, + listAuthenticationMethodTypes, +} from "@/lib/zitadel"; +import { HumanUser, User } from "@zitadel/proto/zitadel/user/v2/user_pb"; +import { AuthenticationMethodType } from "@zitadel/proto/zitadel/user/v2/user_service_pb"; import { getLocale, getTranslations } from "next-intl/server"; -// This configuration shows the given name in the respective IDP button as fallback -const PROVIDER_NAME_MAPPING: { - [provider: string]: string; -} = { - [IdentityProviderType.GOOGLE]: "Google", - [IdentityProviderType.GITHUB]: "GitHub", - [IdentityProviderType.AZURE_AD]: "Microsoft", -}; - export default async function Page(props: { searchParams: Promise>; params: Promise<{ provider: string }>; @@ -20,15 +20,62 @@ export default async function Page(props: { const locale = getLocale(); const t = await getTranslations({ locale, namespace: "idp" }); - const { organization } = searchParams; + const { organization, userId } = searchParams; const branding = await getBrandingSettings(organization); + const loginSettings = await getLoginSettings(organization); + + let authMethods: AuthenticationMethodType[] = []; + let user: User | undefined = undefined; + let human: HumanUser | undefined = undefined; + + if (userId) { + const userResponse = await getUserByID(userId); + if (userResponse) { + user = userResponse.user; + if (user?.type.case === "human") { + human = user.type.value as HumanUser; + } + } + + const authMethodsResponse = await listAuthenticationMethodTypes(userId); + if (authMethodsResponse.authMethodTypes) { + authMethods = authMethodsResponse.authMethodTypes; + } + } + + const params = new URLSearchParams({}); + if (organization) { + params.set("organization", organization); + } + if (userId) { + params.set("userId", userId); + } + return (

{t("loginError.title")}

-

{t("loginError.description")}

+ {t("loginError.description")} + + {userId && authMethods.length && ( + <> + {user && human && ( + + )} + + + + )}
); diff --git a/apps/login/src/components/choose-authenticator-to-login.tsx b/apps/login/src/components/choose-authenticator-to-login.tsx new file mode 100644 index 00000000000..f7e3cdf8f86 --- /dev/null +++ b/apps/login/src/components/choose-authenticator-to-login.tsx @@ -0,0 +1,38 @@ +import { + LoginSettings, + PasskeysType, +} from "@zitadel/proto/zitadel/settings/v2/login_settings_pb"; +import { AuthenticationMethodType } from "@zitadel/proto/zitadel/user/v2/user_service_pb"; +import { useTranslations } from "next-intl"; +import { PASSKEYS, PASSWORD } from "./auth-methods"; + +type Props = { + authMethods: AuthenticationMethodType[]; + params: URLSearchParams; + loginSettings: LoginSettings | undefined; +}; + +export function ChooseAuthenticatorToLogin({ + authMethods, + params, + loginSettings, +}: Props) { + const t = useTranslations("idp"); + + return ( + <> + {authMethods.includes(AuthenticationMethodType.PASSWORD) && + loginSettings?.allowUsernamePassword && ( +
Choose an alternative method to login
+ )} +
+ {authMethods.includes(AuthenticationMethodType.PASSWORD) && + loginSettings?.allowUsernamePassword && + PASSWORD(false, "/password?" + params)} + {authMethods.includes(AuthenticationMethodType.PASSKEY) && + loginSettings?.passkeysType == PasskeysType.ALLOWED && + PASSKEYS(false, "/passkey?" + params)} +
+ + ); +} diff --git a/apps/login/src/lib/server/loginname.ts b/apps/login/src/lib/server/loginname.ts index 65acb80bf04..162c64f02ea 100644 --- a/apps/login/src/lib/server/loginname.ts +++ b/apps/login/src/lib/server/loginname.ts @@ -128,7 +128,7 @@ export async function sendLoginname(command: SendLoginnameCommand) { const identityProviderType = idpTypeToIdentityProviderType(idpType); const provider = idpTypeToSlug(identityProviderType); - const params = new URLSearchParams(); + const params = new URLSearchParams({ userId }); if (command.authRequestId) { params.set("authRequestId", command.authRequestId);