From 3887e268963d5dea4e22bfcf27a9494576b0a577 Mon Sep 17 00:00:00 2001 From: Max Peintner Date: Fri, 20 Dec 2024 11:14:03 +0100 Subject: [PATCH 01/12] add idps to invite flow --- .../app/(login)/authenticator/set/page.tsx | 26 +++++------- .../(login)/idp/[provider]/success/page.tsx | 42 ++++++++++++------- .../login/src/components/sign-in-with-idp.tsx | 4 -- apps/login/src/lib/zitadel.ts | 14 ++++--- 4 files changed, 46 insertions(+), 40 deletions(-) diff --git a/apps/login/src/app/(login)/authenticator/set/page.tsx b/apps/login/src/app/(login)/authenticator/set/page.tsx index 36294c8c..3235afc5 100644 --- a/apps/login/src/app/(login)/authenticator/set/page.tsx +++ b/apps/login/src/app/(login)/authenticator/set/page.tsx @@ -2,10 +2,12 @@ import { Alert } from "@/components/alert"; import { BackButton } from "@/components/back-button"; import { ChooseAuthenticatorToSetup } from "@/components/choose-authenticator-to-setup"; import { DynamicTheme } from "@/components/dynamic-theme"; +import { SignInWithIdp } from "@/components/sign-in-with-idp"; import { UserAvatar } from "@/components/user-avatar"; import { getSessionCookieById } from "@/lib/cookies"; import { loadMostRecentSession } from "@/lib/session"; import { + getActiveIdentityProviders, getBrandingSettings, getLoginSettings, getSession, @@ -86,13 +88,12 @@ export default async function Page(props: { sessionWithData.factors?.user?.organizationId, ); - /* - TODO: Implement after https://github.com/zitadel/zitadel/issues/8981 */ - - // const identityProviders = await getActiveIdentityProviders( - // sessionWithData.factors?.user?.organizationId, - // ).then((resp) => { - // return resp.identityProviders; - // }); + const identityProviders = await getActiveIdentityProviders( + sessionWithData.factors?.user?.organizationId, + true, + ).then((resp) => { + return resp.identityProviders; + }); const params = new URLSearchParams({ initial: "true", // defines that a code is not required and is therefore not shown in the UI @@ -110,10 +111,6 @@ export default async function Page(props: { params.set("authRequestId", authRequestId); } - const host = process.env.VERCEL_URL - ? `https://${process.env.VERCEL_URL}` - : "http://localhost:3000"; - return (
@@ -136,21 +133,18 @@ export default async function Page(props: { > )} - {/* - TODO: Implement after https://github.com/zitadel/zitadel/issues/8981 */} - - {/*

+

or sign in with an Identity Provider

{loginSettings?.allowExternalIdp && identityProviders && ( - )} */} + )}
diff --git a/apps/login/src/app/(login)/idp/[provider]/success/page.tsx b/apps/login/src/app/(login)/idp/[provider]/success/page.tsx index c81d43de..d63b73f9 100644 --- a/apps/login/src/app/(login)/idp/[provider]/success/page.tsx +++ b/apps/login/src/app/(login)/idp/[provider]/success/page.tsx @@ -93,6 +93,26 @@ async function linkingSuccess( ); } +async function linkingFailed(branding?: BrandingSettings) { + const locale = getLocale(); + const t = await getTranslations({ locale, namespace: "idp" }); + + return ( + +
+

{t("linkingError.title")}

+
+ { + + {t("linkingError.description")} + + } +
+
+
+ ); +} + export default async function Page(props: { searchParams: Promise>; params: Promise<{ provider: string }>; @@ -174,20 +194,7 @@ export default async function Page(props: { }, foundUser.userId, ).catch((error) => { - return ( - -
-

{t("linkingError.title")}

-
- { - - {t("linkingError.description")} - - } -
-
-
- ); + return linkingFailed(branding); }); if (idpLink) { @@ -201,7 +208,8 @@ export default async function Page(props: { } } - if (options?.isCreationAllowed && options.isAutoCreation) { + // if link === true, do not create user + if (options?.isCreationAllowed && options.isAutoCreation && !link) { let orgToRegisterOn: string | undefined = organization; let userData: AddHumanUserRequest = @@ -256,6 +264,10 @@ export default async function Page(props: { } } + if (link) { + return linkingFailed(branding); + } + // return login failed if no linking or creation is allowed and no user was found return loginFailed(branding, "No user found"); } diff --git a/apps/login/src/components/sign-in-with-idp.tsx b/apps/login/src/components/sign-in-with-idp.tsx index fd675b62..972f501c 100644 --- a/apps/login/src/components/sign-in-with-idp.tsx +++ b/apps/login/src/components/sign-in-with-idp.tsx @@ -70,11 +70,7 @@ export function SignInWithIdp({ const renderIDPButton = (idp: IdentityProvider) => { const { id, name, type } = idp; const onClick = () => startFlow(id, idpTypeToSlug(type)); - /* - TODO: Implement after https://github.com/zitadel/zitadel/issues/8981 */ - // .filter((idp) => - // linkOnly ? idp.config?.options.isLinkingAllowed : true, - // ) const components: Partial< Record< IdentityProviderType, diff --git a/apps/login/src/lib/zitadel.ts b/apps/login/src/lib/zitadel.ts index aaf0a7c0..849f36de 100644 --- a/apps/login/src/lib/zitadel.ts +++ b/apps/login/src/lib/zitadel.ts @@ -633,11 +633,15 @@ export async function verifyU2FRegistration( return userService.verifyU2FRegistration(request, {}); } -export async function getActiveIdentityProviders(orgId?: string) { - return settingsService.getActiveIdentityProviders( - { ctx: makeReqCtx(orgId) }, - {}, - ); +export async function getActiveIdentityProviders( + orgId?: string, + linking_allowed?: boolean, +) { + const props: any = { ctx: makeReqCtx(orgId) }; + if (linking_allowed) { + props.linkingAllowed = linking_allowed; + } + return settingsService.getActiveIdentityProviders(props, {}); } /** From 09dbaf41063e8309573a514d37d88ec377a7b41a Mon Sep 17 00:00:00 2001 From: Max Peintner Date: Fri, 20 Dec 2024 12:08:02 +0100 Subject: [PATCH 02/12] linking failed page --- apps/login/locales/de.json | 3 ++- apps/login/locales/en.json | 3 ++- apps/login/locales/es.json | 3 ++- apps/login/locales/it.json | 3 ++- apps/login/locales/zh.json | 3 ++- .../app/(login)/authenticator/set/page.tsx | 6 ++--- .../(login)/idp/[provider]/success/page.tsx | 23 +++++++++++++++++++ apps/login/src/lib/server/email.ts | 1 + apps/login/src/lib/server/loginname.ts | 2 ++ 9 files changed, 39 insertions(+), 8 deletions(-) diff --git a/apps/login/locales/de.json b/apps/login/locales/de.json index ba0fce27..5e8756c8 100644 --- a/apps/login/locales/de.json +++ b/apps/login/locales/de.json @@ -183,7 +183,8 @@ "title": "Authentifizierungsmethode auswählen", "description": "Wählen Sie die Methode, mit der Sie sich authentifizieren möchten.", "noMethodsAvailable": "Keine Authentifizierungsmethoden verfügbar", - "allSetup": "Sie haben bereits einen Authentifikator eingerichtet!" + "allSetup": "Sie haben bereits einen Authentifikator eingerichtet!", + "linkWithIDP": "oder verknüpfe mit einem Identitätsanbieter" }, "error": { "unknownContext": "Der Kontext des Benutzers konnte nicht ermittelt werden. Stellen Sie sicher, dass Sie zuerst den Benutzernamen eingeben oder einen loginName als Suchparameter angeben.", diff --git a/apps/login/locales/en.json b/apps/login/locales/en.json index 26530438..3101f222 100644 --- a/apps/login/locales/en.json +++ b/apps/login/locales/en.json @@ -183,7 +183,8 @@ "title": "Choose authentication method", "description": "Select the method you would like to authenticate", "noMethodsAvailable": "No authentication methods available", - "allSetup": "You have already setup an authenticator!" + "allSetup": "You have already setup an authenticator!", + "linkWithIDP": "or link with an Identity Provider" }, "error": { "unknownContext": "Could not get the context of the user. Make sure to enter the username first or provide a loginName as searchParam.", diff --git a/apps/login/locales/es.json b/apps/login/locales/es.json index 35bbb938..5a9b6f63 100644 --- a/apps/login/locales/es.json +++ b/apps/login/locales/es.json @@ -183,7 +183,8 @@ "title": "Seleccionar método de autenticación", "description": "Selecciona el método con el que deseas autenticarte", "noMethodsAvailable": "No hay métodos de autenticación disponibles", - "allSetup": "¡Ya has configurado un autenticador!" + "allSetup": "¡Ya has configurado un autenticador!", + "linkWithIDP": "o vincúlalo con un proveedor de identidad" }, "error": { "unknownContext": "No se pudo obtener el contexto del usuario. Asegúrate de ingresar primero el nombre de usuario o proporcionar un loginName como parámetro de búsqueda.", diff --git a/apps/login/locales/it.json b/apps/login/locales/it.json index 4e21e3dc..1423c43c 100644 --- a/apps/login/locales/it.json +++ b/apps/login/locales/it.json @@ -183,7 +183,8 @@ "title": "Seleziona metodo di autenticazione", "description": "Seleziona il metodo con cui desideri autenticarti", "noMethodsAvailable": "Nessun metodo di autenticazione disponibile", - "allSetup": "Hai già configurato un autenticatore!" + "allSetup": "Hai già configurato un autenticatore!", + "linkWithIDP": "o collega con un Identity Provider" }, "error": { "unknownContext": "Impossibile ottenere il contesto dell'utente. Assicurati di inserire prima il nome utente o di fornire un loginName come parametro di ricerca.", diff --git a/apps/login/locales/zh.json b/apps/login/locales/zh.json index 818a8b44..acd03cc5 100644 --- a/apps/login/locales/zh.json +++ b/apps/login/locales/zh.json @@ -183,7 +183,8 @@ "title": "选择认证方式", "description": "选择您想使用的认证方法", "noMethodsAvailable": "没有可用的认证方法", - "allSetup": "您已经设置好了一个认证器!" + "allSetup": "您已经设置好了一个认证器!", + "linkWithIDP": "或将其与身份提供者关联" }, "error": { "unknownContext": "无法获取用户的上下文。请先输入用户名或提供 loginName 作为搜索参数。", diff --git a/apps/login/src/app/(login)/authenticator/set/page.tsx b/apps/login/src/app/(login)/authenticator/set/page.tsx index 3235afc5..7203484d 100644 --- a/apps/login/src/app/(login)/authenticator/set/page.tsx +++ b/apps/login/src/app/(login)/authenticator/set/page.tsx @@ -133,9 +133,9 @@ export default async function Page(props: { > )} -

- or sign in with an Identity Provider -

+
+

{t("linkWithIDP")}

+
{loginSettings?.allowExternalIdp && identityProviders && ( Date: Fri, 20 Dec 2024 15:54:04 +0100 Subject: [PATCH 03/12] idp pages --- .../(login)/idp/[provider]/success/page.tsx | 107 +++--------------- apps/login/src/app/error.tsx | 21 ++-- .../components/idps/pages/linking-failed.tsx | 28 +++++ .../components/idps/pages/linking-success.tsx | 30 +++++ .../components/idps/pages/login-failed.tsx | 27 +++++ .../components/idps/pages/login-success.tsx | 33 ++++++ 6 files changed, 143 insertions(+), 103 deletions(-) create mode 100644 apps/login/src/components/idps/pages/linking-failed.tsx create mode 100644 apps/login/src/components/idps/pages/linking-success.tsx create mode 100644 apps/login/src/components/idps/pages/login-failed.tsx create mode 100644 apps/login/src/components/idps/pages/login-success.tsx diff --git a/apps/login/src/app/(login)/idp/[provider]/success/page.tsx b/apps/login/src/app/(login)/idp/[provider]/success/page.tsx index 200c3108..4ae6126c 100644 --- a/apps/login/src/app/(login)/idp/[provider]/success/page.tsx +++ b/apps/login/src/app/(login)/idp/[provider]/success/page.tsx @@ -1,6 +1,9 @@ -import { Alert, AlertType } from "@/components/alert"; import { DynamicTheme } from "@/components/dynamic-theme"; import { IdpSignin } from "@/components/idp-signin"; +import { linkingFailed } from "@/components/idps/pages/linking-failed"; +import { linkingSuccess } from "@/components/idps/pages/linking-success"; +import { loginFailed } from "@/components/idps/pages/login-failed"; +import { loginSuccess } from "@/components/idps/pages/login-success"; import { idpTypeToIdentityProviderType, PROVIDER_MAPPING } from "@/lib/idp"; import { addHuman, @@ -15,7 +18,6 @@ import { import { create } from "@zitadel/client"; import { AutoLinkingOption } from "@zitadel/proto/zitadel/idp/v2/idp_pb"; import { OrganizationSchema } from "@zitadel/proto/zitadel/object/v2/object_pb"; -import { BrandingSettings } from "@zitadel/proto/zitadel/settings/v2/branding_settings_pb"; import { AddHumanUserRequest, AddHumanUserRequestSchema, @@ -24,95 +26,6 @@ import { getLocale, getTranslations } from "next-intl/server"; const ORG_SUFFIX_REGEX = /(?<=@)(.+)/; -async function loginFailed(branding?: BrandingSettings, error: string = "") { - const locale = getLocale(); - const t = await getTranslations({ locale, namespace: "idp" }); - - return ( - -
-

{t("loginError.title")}

-

{t("loginError.description")}

- {error && ( -
- {{error}} -
- )} -
-
- ); -} - -async function loginSuccess( - userId: string, - idpIntent: { idpIntentId: string; idpIntentToken: string }, - authRequestId?: string, - branding?: BrandingSettings, -) { - const locale = getLocale(); - const t = await getTranslations({ locale, namespace: "idp" }); - - return ( - -
-

{t("loginSuccess.title")}

-

{t("loginSuccess.description")}

- - -
-
- ); -} - -async function linkingSuccess( - userId: string, - idpIntent: { idpIntentId: string; idpIntentToken: string }, - authRequestId?: string, - branding?: BrandingSettings, -) { - const locale = getLocale(); - const t = await getTranslations({ locale, namespace: "idp" }); - - return ( - -
-

{t("linkingSuccess.title")}

-

{t("linkingSuccess.description")}

- - -
-
- ); -} - -async function linkingFailed(branding?: BrandingSettings) { - const locale = getLocale(); - const t = await getTranslations({ locale, namespace: "idp" }); - - return ( - -
-

{t("linkingError.title")}

-
- { - - {t("linkingError.description")} - - } -
-
-
- ); -} - export default async function Page(props: { searchParams: Promise>; params: Promise<{ provider: string }>; @@ -168,9 +81,13 @@ export default async function Page(props: { userName: idpInformation.userName, }, userId, - ); + ).catch((error) => { + console.error(error); + return linkingFailed(branding); + }); if (!idpLink) { + console.log("linking failed"); return linkingFailed(branding); } else { return linkingSuccess( @@ -217,10 +134,12 @@ export default async function Page(props: { }, foundUser.userId, ).catch((error) => { + console.error(error); return linkingFailed(branding); }); - - if (idpLink) { + if (!idpLink) { + return linkingFailed(branding); + } else { return linkingSuccess( foundUser.userId, { idpIntentId: id, idpIntentToken: token }, diff --git a/apps/login/src/app/error.tsx b/apps/login/src/app/error.tsx index bee6516a..d4757866 100644 --- a/apps/login/src/app/error.tsx +++ b/apps/login/src/app/error.tsx @@ -2,6 +2,7 @@ import { Boundary } from "@/components/boundary"; import { Button } from "@/components/button"; +import { LanguageProvider } from "@/components/language-provider"; import { useTranslations } from "next-intl"; import { useEffect } from "react"; @@ -13,15 +14,17 @@ export default function Error({ error, reset }: any) { const t = useTranslations("error"); return ( - -
-
- Error: {error?.message} + + +
+
+ Error: {error?.message} +
+
+ +
-
- -
-
- + + ); } diff --git a/apps/login/src/components/idps/pages/linking-failed.tsx b/apps/login/src/components/idps/pages/linking-failed.tsx new file mode 100644 index 00000000..94678fb2 --- /dev/null +++ b/apps/login/src/components/idps/pages/linking-failed.tsx @@ -0,0 +1,28 @@ +"use client"; + +import { LanguageProvider } from "@/components/language-provider"; +import { BrandingSettings } from "@zitadel/proto/zitadel/settings/v2/branding_settings_pb"; +import { useTranslations } from "next-intl"; +import { Alert, AlertType } from "../../alert"; +import { DynamicTheme } from "../../dynamic-theme"; + +export function linkingFailed(branding?: BrandingSettings) { + const t = useTranslations("idp"); + + return ( + + +
+

{t("linkingError.title")}

+
+ { + + {t("linkingError.description")} + + } +
+
+
+
+ ); +} diff --git a/apps/login/src/components/idps/pages/linking-success.tsx b/apps/login/src/components/idps/pages/linking-success.tsx new file mode 100644 index 00000000..39671d8f --- /dev/null +++ b/apps/login/src/components/idps/pages/linking-success.tsx @@ -0,0 +1,30 @@ +"use client"; + +import { BrandingSettings } from "@zitadel/proto/zitadel/settings/v2/branding_settings_pb"; +import { useTranslations } from "next-intl"; +import { DynamicTheme } from "../../dynamic-theme"; +import { IdpSignin } from "../../idp-signin"; + +export function linkingSuccess( + userId: string, + idpIntent: { idpIntentId: string; idpIntentToken: string }, + authRequestId?: string, + branding?: BrandingSettings, +) { + const t = useTranslations("idp"); + + return ( + +
+

{t("linkingSuccess.title")}

+

{t("linkingSuccess.description")}

+ + +
+
+ ); +} diff --git a/apps/login/src/components/idps/pages/login-failed.tsx b/apps/login/src/components/idps/pages/login-failed.tsx new file mode 100644 index 00000000..5bddf29a --- /dev/null +++ b/apps/login/src/components/idps/pages/login-failed.tsx @@ -0,0 +1,27 @@ +"use client"; + +import { LanguageProvider } from "@/components/language-provider"; +import { BrandingSettings } from "@zitadel/proto/zitadel/settings/v2/branding_settings_pb"; +import { useTranslations } from "next-intl"; +import { Alert, AlertType } from "../../alert"; +import { DynamicTheme } from "../../dynamic-theme"; + +export function loginFailed(branding?: BrandingSettings, error: string = "") { + const t = useTranslations("idp"); + + return ( + + +
+

{t("loginError.title")}

+

{t("loginError.description")}

+ {error && ( +
+ {{error}} +
+ )} +
+
+
+ ); +} diff --git a/apps/login/src/components/idps/pages/login-success.tsx b/apps/login/src/components/idps/pages/login-success.tsx new file mode 100644 index 00000000..39aa71c6 --- /dev/null +++ b/apps/login/src/components/idps/pages/login-success.tsx @@ -0,0 +1,33 @@ +"use client"; + +import { LanguageProvider } from "@/components/language-provider"; +import { BrandingSettings } from "@zitadel/proto/zitadel/settings/v2/branding_settings_pb"; +import { useTranslations } from "next-intl"; +import { DynamicTheme } from "../../dynamic-theme"; +import { IdpSignin } from "../../idp-signin"; + +export function loginSuccess( + userId: string, + idpIntent: { idpIntentId: string; idpIntentToken: string }, + authRequestId?: string, + branding?: BrandingSettings, +) { + const t = useTranslations("idp"); + + return ( + + +
+

{t("loginSuccess.title")}

+

{t("loginSuccess.description")}

+ + +
+
+
+ ); +} From d3111d3ba3f1bb6c64d8edaa05b14f412e614eea Mon Sep 17 00:00:00 2001 From: Max Peintner Date: Mon, 23 Dec 2024 09:32:01 +0100 Subject: [PATCH 04/12] handle error when linking --- .../(login)/idp/[provider]/failure/page.tsx | 2 +- .../(login)/idp/[provider]/success/page.tsx | 43 +++++++++++-------- .../components/idps/pages/linking-failed.tsx | 9 ++-- .../components/idps/pages/linking-success.tsx | 9 ++-- .../components/idps/pages/login-failed.tsx | 12 +++--- .../components/idps/pages/login-success.tsx | 9 ++-- 6 files changed, 45 insertions(+), 39 deletions(-) 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 a8bc6d9c..a3cc0ee8 100644 --- a/apps/login/src/app/(login)/idp/[provider]/failure/page.tsx +++ b/apps/login/src/app/(login)/idp/[provider]/failure/page.tsx @@ -28,7 +28,7 @@ export default async function Page(props: {

{t("loginError.title")}

-
{t("loginError.description")}
+

{t("loginError.description")}

); diff --git a/apps/login/src/app/(login)/idp/[provider]/success/page.tsx b/apps/login/src/app/(login)/idp/[provider]/success/page.tsx index 4ae6126c..cc3f7129 100644 --- a/apps/login/src/app/(login)/idp/[provider]/success/page.tsx +++ b/apps/login/src/app/(login)/idp/[provider]/success/page.tsx @@ -74,17 +74,20 @@ export default async function Page(props: { if (link && options?.isLinkingAllowed) { console.log(userId); - const idpLink = await addIDPLink( - { - id: idpInformation.idpId, - userId: idpInformation.userId, - userName: idpInformation.userName, - }, - userId, - ).catch((error) => { + let idpLink; + try { + idpLink = await addIDPLink( + { + id: idpInformation.idpId, + userId: idpInformation.userId, + userName: idpInformation.userName, + }, + userId, + ); + } catch (error) { console.error(error); return linkingFailed(branding); - }); + } if (!idpLink) { console.log("linking failed"); @@ -126,17 +129,21 @@ export default async function Page(props: { } if (foundUser) { - const idpLink = await addIDPLink( - { - id: idpInformation.idpId, - userId: idpInformation.userId, - userName: idpInformation.userName, - }, - foundUser.userId, - ).catch((error) => { + let idpLink; + try { + idpLink = await addIDPLink( + { + id: idpInformation.idpId, + userId: idpInformation.userId, + userName: idpInformation.userName, + }, + foundUser.userId, + ); + } catch (error) { console.error(error); return linkingFailed(branding); - }); + } + if (!idpLink) { return linkingFailed(branding); } else { diff --git a/apps/login/src/components/idps/pages/linking-failed.tsx b/apps/login/src/components/idps/pages/linking-failed.tsx index 94678fb2..82d6a067 100644 --- a/apps/login/src/components/idps/pages/linking-failed.tsx +++ b/apps/login/src/components/idps/pages/linking-failed.tsx @@ -1,13 +1,12 @@ -"use client"; - import { LanguageProvider } from "@/components/language-provider"; import { BrandingSettings } from "@zitadel/proto/zitadel/settings/v2/branding_settings_pb"; -import { useTranslations } from "next-intl"; +import { getLocale, getTranslations } from "next-intl/server"; import { Alert, AlertType } from "../../alert"; import { DynamicTheme } from "../../dynamic-theme"; -export function linkingFailed(branding?: BrandingSettings) { - const t = useTranslations("idp"); +export async function linkingFailed(branding?: BrandingSettings) { + const locale = getLocale(); + const t = await getTranslations({ locale, namespace: "idp" }); return ( diff --git a/apps/login/src/components/idps/pages/linking-success.tsx b/apps/login/src/components/idps/pages/linking-success.tsx index 39671d8f..66098ed6 100644 --- a/apps/login/src/components/idps/pages/linking-success.tsx +++ b/apps/login/src/components/idps/pages/linking-success.tsx @@ -1,17 +1,16 @@ -"use client"; - import { BrandingSettings } from "@zitadel/proto/zitadel/settings/v2/branding_settings_pb"; -import { useTranslations } from "next-intl"; +import { getLocale, getTranslations } from "next-intl/server"; import { DynamicTheme } from "../../dynamic-theme"; import { IdpSignin } from "../../idp-signin"; -export function linkingSuccess( +export async function linkingSuccess( userId: string, idpIntent: { idpIntentId: string; idpIntentToken: string }, authRequestId?: string, branding?: BrandingSettings, ) { - const t = useTranslations("idp"); + const locale = getLocale(); + const t = await getTranslations({ locale, namespace: "idp" }); return ( diff --git a/apps/login/src/components/idps/pages/login-failed.tsx b/apps/login/src/components/idps/pages/login-failed.tsx index 5bddf29a..ea8b22cc 100644 --- a/apps/login/src/components/idps/pages/login-failed.tsx +++ b/apps/login/src/components/idps/pages/login-failed.tsx @@ -1,13 +1,15 @@ -"use client"; - import { LanguageProvider } from "@/components/language-provider"; import { BrandingSettings } from "@zitadel/proto/zitadel/settings/v2/branding_settings_pb"; -import { useTranslations } from "next-intl"; +import { getLocale, getTranslations } from "next-intl/server"; import { Alert, AlertType } from "../../alert"; import { DynamicTheme } from "../../dynamic-theme"; -export function loginFailed(branding?: BrandingSettings, error: string = "") { - const t = useTranslations("idp"); +export async function loginFailed( + branding?: BrandingSettings, + error: string = "", +) { + const locale = getLocale(); + const t = await getTranslations({ locale, namespace: "idp" }); return ( diff --git a/apps/login/src/components/idps/pages/login-success.tsx b/apps/login/src/components/idps/pages/login-success.tsx index 39aa71c6..62da260c 100644 --- a/apps/login/src/components/idps/pages/login-success.tsx +++ b/apps/login/src/components/idps/pages/login-success.tsx @@ -1,18 +1,17 @@ -"use client"; - import { LanguageProvider } from "@/components/language-provider"; import { BrandingSettings } from "@zitadel/proto/zitadel/settings/v2/branding_settings_pb"; -import { useTranslations } from "next-intl"; +import { getLocale, getTranslations } from "next-intl/server"; import { DynamicTheme } from "../../dynamic-theme"; import { IdpSignin } from "../../idp-signin"; -export function loginSuccess( +export async function loginSuccess( userId: string, idpIntent: { idpIntentId: string; idpIntentToken: string }, authRequestId?: string, branding?: BrandingSettings, ) { - const t = useTranslations("idp"); + const locale = getLocale(); + const t = await getTranslations({ locale, namespace: "idp" }); return ( From 2bb46137ceeddcbae109ffef5cf110e30fd0ebe1 Mon Sep 17 00:00:00 2001 From: Max Peintner Date: Mon, 23 Dec 2024 09:35:07 +0100 Subject: [PATCH 05/12] rm logs --- apps/login/src/app/(login)/idp/[provider]/success/page.tsx | 4 ---- 1 file changed, 4 deletions(-) diff --git a/apps/login/src/app/(login)/idp/[provider]/success/page.tsx b/apps/login/src/app/(login)/idp/[provider]/success/page.tsx index cc3f7129..3049ce83 100644 --- a/apps/login/src/app/(login)/idp/[provider]/success/page.tsx +++ b/apps/login/src/app/(login)/idp/[provider]/success/page.tsx @@ -73,7 +73,6 @@ export default async function Page(props: { const providerType = idpTypeToIdentityProviderType(idp.type); if (link && options?.isLinkingAllowed) { - console.log(userId); let idpLink; try { idpLink = await addIDPLink( @@ -85,12 +84,10 @@ export default async function Page(props: { userId, ); } catch (error) { - console.error(error); return linkingFailed(branding); } if (!idpLink) { - console.log("linking failed"); return linkingFailed(branding); } else { return linkingSuccess( @@ -140,7 +137,6 @@ export default async function Page(props: { foundUser.userId, ); } catch (error) { - console.error(error); return linkingFailed(branding); } From 0546a1c06e6d1ae012f3382d9cf19b33dca9ac02 Mon Sep 17 00:00:00 2001 From: Max Peintner Date: Mon, 23 Dec 2024 09:36:19 +0100 Subject: [PATCH 06/12] rm redundant language providers --- apps/login/src/app/error.tsx | 21 +++++++--------- .../components/idps/pages/linking-failed.tsx | 25 ++++++++----------- .../components/idps/pages/login-failed.tsx | 25 ++++++++----------- .../components/idps/pages/login-success.tsx | 25 ++++++++----------- 4 files changed, 42 insertions(+), 54 deletions(-) diff --git a/apps/login/src/app/error.tsx b/apps/login/src/app/error.tsx index d4757866..bee6516a 100644 --- a/apps/login/src/app/error.tsx +++ b/apps/login/src/app/error.tsx @@ -2,7 +2,6 @@ import { Boundary } from "@/components/boundary"; import { Button } from "@/components/button"; -import { LanguageProvider } from "@/components/language-provider"; import { useTranslations } from "next-intl"; import { useEffect } from "react"; @@ -14,17 +13,15 @@ export default function Error({ error, reset }: any) { const t = useTranslations("error"); return ( - - -
-
- Error: {error?.message} -
-
- -
+ +
+
+ Error: {error?.message}
- - +
+ +
+
+
); } diff --git a/apps/login/src/components/idps/pages/linking-failed.tsx b/apps/login/src/components/idps/pages/linking-failed.tsx index 82d6a067..bb632846 100644 --- a/apps/login/src/components/idps/pages/linking-failed.tsx +++ b/apps/login/src/components/idps/pages/linking-failed.tsx @@ -1,4 +1,3 @@ -import { LanguageProvider } from "@/components/language-provider"; import { BrandingSettings } from "@zitadel/proto/zitadel/settings/v2/branding_settings_pb"; import { getLocale, getTranslations } from "next-intl/server"; import { Alert, AlertType } from "../../alert"; @@ -9,19 +8,17 @@ export async function linkingFailed(branding?: BrandingSettings) { const t = await getTranslations({ locale, namespace: "idp" }); return ( - - -
-

{t("linkingError.title")}

-
- { - - {t("linkingError.description")} - - } -
+ +
+

{t("linkingError.title")}

+
+ { + + {t("linkingError.description")} + + }
- - +
+
); } diff --git a/apps/login/src/components/idps/pages/login-failed.tsx b/apps/login/src/components/idps/pages/login-failed.tsx index ea8b22cc..8da5eee3 100644 --- a/apps/login/src/components/idps/pages/login-failed.tsx +++ b/apps/login/src/components/idps/pages/login-failed.tsx @@ -1,4 +1,3 @@ -import { LanguageProvider } from "@/components/language-provider"; import { BrandingSettings } from "@zitadel/proto/zitadel/settings/v2/branding_settings_pb"; import { getLocale, getTranslations } from "next-intl/server"; import { Alert, AlertType } from "../../alert"; @@ -12,18 +11,16 @@ export async function loginFailed( const t = await getTranslations({ locale, namespace: "idp" }); return ( - - -
-

{t("loginError.title")}

-

{t("loginError.description")}

- {error && ( -
- {{error}} -
- )} -
-
-
+ +
+

{t("loginError.title")}

+

{t("loginError.description")}

+ {error && ( +
+ {{error}} +
+ )} +
+
); } diff --git a/apps/login/src/components/idps/pages/login-success.tsx b/apps/login/src/components/idps/pages/login-success.tsx index 62da260c..3a9a3719 100644 --- a/apps/login/src/components/idps/pages/login-success.tsx +++ b/apps/login/src/components/idps/pages/login-success.tsx @@ -1,4 +1,3 @@ -import { LanguageProvider } from "@/components/language-provider"; import { BrandingSettings } from "@zitadel/proto/zitadel/settings/v2/branding_settings_pb"; import { getLocale, getTranslations } from "next-intl/server"; import { DynamicTheme } from "../../dynamic-theme"; @@ -14,19 +13,17 @@ export async function loginSuccess( const t = await getTranslations({ locale, namespace: "idp" }); return ( - - -
-

{t("loginSuccess.title")}

-

{t("loginSuccess.description")}

+ +
+

{t("loginSuccess.title")}

+

{t("loginSuccess.description")}

- -
-
- + +
+
); } From d59b2ed612801735f903ade05ce48a6b130fb1a2 Mon Sep 17 00:00:00 2001 From: Max Peintner Date: Tue, 24 Dec 2024 11:40:37 +0100 Subject: [PATCH 07/12] remove unnec initializer --- apps/login/src/components/idps/pages/login-failed.tsx | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/apps/login/src/components/idps/pages/login-failed.tsx b/apps/login/src/components/idps/pages/login-failed.tsx index 8da5eee3..e4187af7 100644 --- a/apps/login/src/components/idps/pages/login-failed.tsx +++ b/apps/login/src/components/idps/pages/login-failed.tsx @@ -3,10 +3,7 @@ import { getLocale, getTranslations } from "next-intl/server"; import { Alert, AlertType } from "../../alert"; import { DynamicTheme } from "../../dynamic-theme"; -export async function loginFailed( - branding?: BrandingSettings, - error: string = "", -) { +export async function loginFailed(branding?: BrandingSettings, error?: string) { const locale = getLocale(); const t = await getTranslations({ locale, namespace: "idp" }); From 52d97533580d0909138fd6a3033af76da0f8e6ff Mon Sep 17 00:00:00 2001 From: Max Peintner Date: Fri, 27 Dec 2024 11:43:12 +0100 Subject: [PATCH 08/12] Update apps/login/src/lib/server/loginname.ts Co-authored-by: Elio Bischof --- apps/login/src/lib/server/loginname.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/apps/login/src/lib/server/loginname.ts b/apps/login/src/lib/server/loginname.ts index 5100541a..295f9b45 100644 --- a/apps/login/src/lib/server/loginname.ts +++ b/apps/login/src/lib/server/loginname.ts @@ -170,8 +170,6 @@ export async function sendLoginname(command: SendLoginnameCommand) { session.factors?.user?.id, ); - console.log(methods); - if (!methods.authMethodTypes || !methods.authMethodTypes.length) { if ( potentialUsers[0].type.case === "human" && From aa6a5971910f9963467d3f73def783c7e072cd53 Mon Sep 17 00:00:00 2001 From: Max Peintner Date: Fri, 27 Dec 2024 11:48:11 +0100 Subject: [PATCH 09/12] fix: ordering of conditions --- .../src/app/(login)/idp/[provider]/success/page.tsx | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/apps/login/src/app/(login)/idp/[provider]/success/page.tsx b/apps/login/src/app/(login)/idp/[provider]/success/page.tsx index 3049ce83..d84f5ac5 100644 --- a/apps/login/src/app/(login)/idp/[provider]/success/page.tsx +++ b/apps/login/src/app/(login)/idp/[provider]/success/page.tsx @@ -153,8 +153,11 @@ export default async function Page(props: { } } - // if link === true, do not create user - if (options?.isCreationAllowed && options.isAutoCreation && !link) { + if (link) { + return linkingFailed(branding); + } + + if (options?.isCreationAllowed && options.isAutoCreation) { let orgToRegisterOn: string | undefined = organization; let userData: AddHumanUserRequest = @@ -209,10 +212,6 @@ export default async function Page(props: { } } - if (link) { - return linkingFailed(branding); - } - // return login failed if no linking or creation is allowed and no user was found return loginFailed(branding, "No user found"); } From ab2136d5abc5f765f138b1de06da690bf1416e90 Mon Sep 17 00:00:00 2001 From: Max Peintner Date: Fri, 27 Dec 2024 11:55:35 +0100 Subject: [PATCH 10/12] show error --- .../(login)/idp/[provider]/success/page.tsx | 2 ++ .../components/idps/pages/linking-failed.tsx | 18 ++++++++++-------- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/apps/login/src/app/(login)/idp/[provider]/success/page.tsx b/apps/login/src/app/(login)/idp/[provider]/success/page.tsx index d84f5ac5..8b0d0c25 100644 --- a/apps/login/src/app/(login)/idp/[provider]/success/page.tsx +++ b/apps/login/src/app/(login)/idp/[provider]/success/page.tsx @@ -84,6 +84,7 @@ export default async function Page(props: { userId, ); } catch (error) { + console.error(error); return linkingFailed(branding); } @@ -137,6 +138,7 @@ export default async function Page(props: { foundUser.userId, ); } catch (error) { + console.error(error); return linkingFailed(branding); } diff --git a/apps/login/src/components/idps/pages/linking-failed.tsx b/apps/login/src/components/idps/pages/linking-failed.tsx index bb632846..f4016a33 100644 --- a/apps/login/src/components/idps/pages/linking-failed.tsx +++ b/apps/login/src/components/idps/pages/linking-failed.tsx @@ -3,7 +3,10 @@ import { getLocale, getTranslations } from "next-intl/server"; import { Alert, AlertType } from "../../alert"; import { DynamicTheme } from "../../dynamic-theme"; -export async function linkingFailed(branding?: BrandingSettings) { +export async function linkingFailed( + branding?: BrandingSettings, + error?: string, +) { const locale = getLocale(); const t = await getTranslations({ locale, namespace: "idp" }); @@ -11,13 +14,12 @@ export async function linkingFailed(branding?: BrandingSettings) {

{t("linkingError.title")}

-
- { - - {t("linkingError.description")} - - } -
+

{t("linkingError.description")}

+ {error && ( +
+ {{error}} +
+ )}
); From d8532140bc6d7001914fb922e72c89de705f1940 Mon Sep 17 00:00:00 2001 From: Max Peintner Date: Fri, 27 Dec 2024 12:09:16 +0100 Subject: [PATCH 11/12] cleanup --- .../src/app/(login)/idp/[provider]/success/page.tsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/login/src/app/(login)/idp/[provider]/success/page.tsx b/apps/login/src/app/(login)/idp/[provider]/success/page.tsx index 8b0d0c25..296a25bb 100644 --- a/apps/login/src/app/(login)/idp/[provider]/success/page.tsx +++ b/apps/login/src/app/(login)/idp/[provider]/success/page.tsx @@ -72,7 +72,11 @@ export default async function Page(props: { const providerType = idpTypeToIdentityProviderType(idp.type); - if (link && options?.isLinkingAllowed) { + if (link) { + if (!options?.isLinkingAllowed) { + return linkingFailed(branding, "Linking is no longer allowed"); + } + let idpLink; try { idpLink = await addIDPLink( @@ -155,10 +159,6 @@ export default async function Page(props: { } } - if (link) { - return linkingFailed(branding); - } - if (options?.isCreationAllowed && options.isAutoCreation) { let orgToRegisterOn: string | undefined = organization; From 36187ecdc45f84dc4fb06339bd0e5375cefe13a8 Mon Sep 17 00:00:00 2001 From: Elio Bischof Date: Fri, 27 Dec 2024 12:13:07 +0100 Subject: [PATCH 12/12] Update apps/login/src/app/(login)/idp/[provider]/success/page.tsx --- apps/login/src/app/(login)/idp/[provider]/success/page.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/login/src/app/(login)/idp/[provider]/success/page.tsx b/apps/login/src/app/(login)/idp/[provider]/success/page.tsx index 296a25bb..0de29fd1 100644 --- a/apps/login/src/app/(login)/idp/[provider]/success/page.tsx +++ b/apps/login/src/app/(login)/idp/[provider]/success/page.tsx @@ -74,6 +74,7 @@ export default async function Page(props: { if (link) { if (!options?.isLinkingAllowed) { + // linking was probably disallowed since the invitation was created return linkingFailed(branding, "Linking is no longer allowed"); }