mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-12 10:27:33 +00:00
Merge pull request #323 from zitadel/idp-invite
fix: add IDPs to invite flow
This commit is contained in:
@@ -183,7 +183,8 @@
|
|||||||
"title": "Authentifizierungsmethode auswählen",
|
"title": "Authentifizierungsmethode auswählen",
|
||||||
"description": "Wählen Sie die Methode, mit der Sie sich authentifizieren möchten.",
|
"description": "Wählen Sie die Methode, mit der Sie sich authentifizieren möchten.",
|
||||||
"noMethodsAvailable": "Keine Authentifizierungsmethoden verfügbar",
|
"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": {
|
"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.",
|
"unknownContext": "Der Kontext des Benutzers konnte nicht ermittelt werden. Stellen Sie sicher, dass Sie zuerst den Benutzernamen eingeben oder einen loginName als Suchparameter angeben.",
|
||||||
|
@@ -183,7 +183,8 @@
|
|||||||
"title": "Choose authentication method",
|
"title": "Choose authentication method",
|
||||||
"description": "Select the method you would like to authenticate",
|
"description": "Select the method you would like to authenticate",
|
||||||
"noMethodsAvailable": "No authentication methods available",
|
"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": {
|
"error": {
|
||||||
"unknownContext": "Could not get the context of the user. Make sure to enter the username first or provide a loginName as searchParam.",
|
"unknownContext": "Could not get the context of the user. Make sure to enter the username first or provide a loginName as searchParam.",
|
||||||
|
@@ -183,7 +183,8 @@
|
|||||||
"title": "Seleccionar método de autenticación",
|
"title": "Seleccionar método de autenticación",
|
||||||
"description": "Selecciona el método con el que deseas autenticarte",
|
"description": "Selecciona el método con el que deseas autenticarte",
|
||||||
"noMethodsAvailable": "No hay métodos de autenticación disponibles",
|
"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": {
|
"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.",
|
"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.",
|
||||||
|
@@ -183,7 +183,8 @@
|
|||||||
"title": "Seleziona metodo di autenticazione",
|
"title": "Seleziona metodo di autenticazione",
|
||||||
"description": "Seleziona il metodo con cui desideri autenticarti",
|
"description": "Seleziona il metodo con cui desideri autenticarti",
|
||||||
"noMethodsAvailable": "Nessun metodo di autenticazione disponibile",
|
"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": {
|
"error": {
|
||||||
"unknownContext": "Impossibile ottenere il contesto dell'utente. Assicurati di inserire prima il nome utente o di fornire un loginName come parametro di ricerca.",
|
"unknownContext": "Impossibile ottenere il contesto dell'utente. Assicurati di inserire prima il nome utente o di fornire un loginName come parametro di ricerca.",
|
||||||
|
@@ -183,7 +183,8 @@
|
|||||||
"title": "选择认证方式",
|
"title": "选择认证方式",
|
||||||
"description": "选择您想使用的认证方法",
|
"description": "选择您想使用的认证方法",
|
||||||
"noMethodsAvailable": "没有可用的认证方法",
|
"noMethodsAvailable": "没有可用的认证方法",
|
||||||
"allSetup": "您已经设置好了一个认证器!"
|
"allSetup": "您已经设置好了一个认证器!",
|
||||||
|
"linkWithIDP": "或将其与身份提供者关联"
|
||||||
},
|
},
|
||||||
"error": {
|
"error": {
|
||||||
"unknownContext": "无法获取用户的上下文。请先输入用户名或提供 loginName 作为搜索参数。",
|
"unknownContext": "无法获取用户的上下文。请先输入用户名或提供 loginName 作为搜索参数。",
|
||||||
|
@@ -2,10 +2,12 @@ import { Alert } from "@/components/alert";
|
|||||||
import { BackButton } from "@/components/back-button";
|
import { BackButton } from "@/components/back-button";
|
||||||
import { ChooseAuthenticatorToSetup } from "@/components/choose-authenticator-to-setup";
|
import { ChooseAuthenticatorToSetup } from "@/components/choose-authenticator-to-setup";
|
||||||
import { DynamicTheme } from "@/components/dynamic-theme";
|
import { DynamicTheme } from "@/components/dynamic-theme";
|
||||||
|
import { SignInWithIdp } from "@/components/sign-in-with-idp";
|
||||||
import { UserAvatar } from "@/components/user-avatar";
|
import { UserAvatar } from "@/components/user-avatar";
|
||||||
import { getSessionCookieById } from "@/lib/cookies";
|
import { getSessionCookieById } from "@/lib/cookies";
|
||||||
import { loadMostRecentSession } from "@/lib/session";
|
import { loadMostRecentSession } from "@/lib/session";
|
||||||
import {
|
import {
|
||||||
|
getActiveIdentityProviders,
|
||||||
getBrandingSettings,
|
getBrandingSettings,
|
||||||
getLoginSettings,
|
getLoginSettings,
|
||||||
getSession,
|
getSession,
|
||||||
@@ -86,13 +88,12 @@ export default async function Page(props: {
|
|||||||
sessionWithData.factors?.user?.organizationId,
|
sessionWithData.factors?.user?.organizationId,
|
||||||
);
|
);
|
||||||
|
|
||||||
/* - TODO: Implement after https://github.com/zitadel/zitadel/issues/8981 */
|
const identityProviders = await getActiveIdentityProviders(
|
||||||
|
sessionWithData.factors?.user?.organizationId,
|
||||||
// const identityProviders = await getActiveIdentityProviders(
|
true,
|
||||||
// sessionWithData.factors?.user?.organizationId,
|
).then((resp) => {
|
||||||
// ).then((resp) => {
|
return resp.identityProviders;
|
||||||
// return resp.identityProviders;
|
});
|
||||||
// });
|
|
||||||
|
|
||||||
const params = new URLSearchParams({
|
const params = new URLSearchParams({
|
||||||
initial: "true", // defines that a code is not required and is therefore not shown in the UI
|
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);
|
params.set("authRequestId", authRequestId);
|
||||||
}
|
}
|
||||||
|
|
||||||
const host = process.env.VERCEL_URL
|
|
||||||
? `https://${process.env.VERCEL_URL}`
|
|
||||||
: "http://localhost:3000";
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DynamicTheme branding={branding}>
|
<DynamicTheme branding={branding}>
|
||||||
<div className="flex flex-col items-center space-y-4">
|
<div className="flex flex-col items-center space-y-4">
|
||||||
@@ -136,21 +133,18 @@ export default async function Page(props: {
|
|||||||
></ChooseAuthenticatorToSetup>
|
></ChooseAuthenticatorToSetup>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* - TODO: Implement after https://github.com/zitadel/zitadel/issues/8981 */}
|
<div className="py-3 flex flex-col">
|
||||||
|
<p className="ztdl-p text-center">{t("linkWithIDP")}</p>
|
||||||
{/* <p className="ztdl-p text-center">
|
</div>
|
||||||
or sign in with an Identity Provider
|
|
||||||
</p>
|
|
||||||
|
|
||||||
{loginSettings?.allowExternalIdp && identityProviders && (
|
{loginSettings?.allowExternalIdp && identityProviders && (
|
||||||
<SignInWithIdp
|
<SignInWithIdp
|
||||||
host={host}
|
|
||||||
identityProviders={identityProviders}
|
identityProviders={identityProviders}
|
||||||
authRequestId={authRequestId}
|
authRequestId={authRequestId}
|
||||||
organization={sessionWithData.factors?.user?.organizationId}
|
organization={sessionWithData.factors?.user?.organizationId}
|
||||||
linkOnly={true} // tell the callback function to just link the IDP and not login, to get an error when user is already available
|
linkOnly={true} // tell the callback function to just link the IDP and not login, to get an error when user is already available
|
||||||
></SignInWithIdp>
|
></SignInWithIdp>
|
||||||
)} */}
|
)}
|
||||||
|
|
||||||
<div className="mt-8 flex w-full flex-row items-center">
|
<div className="mt-8 flex w-full flex-row items-center">
|
||||||
<BackButton />
|
<BackButton />
|
||||||
|
@@ -28,7 +28,7 @@ export default async function Page(props: {
|
|||||||
<DynamicTheme branding={branding}>
|
<DynamicTheme branding={branding}>
|
||||||
<div className="flex flex-col items-center space-y-4">
|
<div className="flex flex-col items-center space-y-4">
|
||||||
<h1>{t("loginError.title")}</h1>
|
<h1>{t("loginError.title")}</h1>
|
||||||
<div>{t("loginError.description")}</div>
|
<p className="ztdl-p">{t("loginError.description")}</p>
|
||||||
</div>
|
</div>
|
||||||
</DynamicTheme>
|
</DynamicTheme>
|
||||||
);
|
);
|
||||||
|
@@ -1,6 +1,9 @@
|
|||||||
import { Alert, AlertType } from "@/components/alert";
|
|
||||||
import { DynamicTheme } from "@/components/dynamic-theme";
|
import { DynamicTheme } from "@/components/dynamic-theme";
|
||||||
import { IdpSignin } from "@/components/idp-signin";
|
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 { idpTypeToIdentityProviderType, PROVIDER_MAPPING } from "@/lib/idp";
|
||||||
import {
|
import {
|
||||||
addHuman,
|
addHuman,
|
||||||
@@ -15,7 +18,6 @@ import {
|
|||||||
import { create } from "@zitadel/client";
|
import { create } from "@zitadel/client";
|
||||||
import { AutoLinkingOption } from "@zitadel/proto/zitadel/idp/v2/idp_pb";
|
import { AutoLinkingOption } from "@zitadel/proto/zitadel/idp/v2/idp_pb";
|
||||||
import { OrganizationSchema } from "@zitadel/proto/zitadel/object/v2/object_pb";
|
import { OrganizationSchema } from "@zitadel/proto/zitadel/object/v2/object_pb";
|
||||||
import { BrandingSettings } from "@zitadel/proto/zitadel/settings/v2/branding_settings_pb";
|
|
||||||
import {
|
import {
|
||||||
AddHumanUserRequest,
|
AddHumanUserRequest,
|
||||||
AddHumanUserRequestSchema,
|
AddHumanUserRequestSchema,
|
||||||
@@ -24,75 +26,6 @@ import { getLocale, getTranslations } from "next-intl/server";
|
|||||||
|
|
||||||
const ORG_SUFFIX_REGEX = /(?<=@)(.+)/;
|
const ORG_SUFFIX_REGEX = /(?<=@)(.+)/;
|
||||||
|
|
||||||
async function loginFailed(branding?: BrandingSettings, error: string = "") {
|
|
||||||
const locale = getLocale();
|
|
||||||
const t = await getTranslations({ locale, namespace: "idp" });
|
|
||||||
|
|
||||||
return (
|
|
||||||
<DynamicTheme branding={branding}>
|
|
||||||
<div className="flex flex-col items-center space-y-4">
|
|
||||||
<h1>{t("loginError.title")}</h1>
|
|
||||||
<p className="ztdl-p">{t("loginError.description")}</p>
|
|
||||||
{error && (
|
|
||||||
<div className="w-full">
|
|
||||||
{<Alert type={AlertType.ALERT}>{error}</Alert>}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</DynamicTheme>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
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 (
|
|
||||||
<DynamicTheme branding={branding}>
|
|
||||||
<div className="flex flex-col items-center space-y-4">
|
|
||||||
<h1>{t("loginSuccess.title")}</h1>
|
|
||||||
<p className="ztdl-p">{t("loginSuccess.description")}</p>
|
|
||||||
|
|
||||||
<IdpSignin
|
|
||||||
userId={userId}
|
|
||||||
idpIntent={idpIntent}
|
|
||||||
authRequestId={authRequestId}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</DynamicTheme>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
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 (
|
|
||||||
<DynamicTheme branding={branding}>
|
|
||||||
<div className="flex flex-col items-center space-y-4">
|
|
||||||
<h1>{t("linkingSuccess.title")}</h1>
|
|
||||||
<p className="ztdl-p">{t("linkingSuccess.description")}</p>
|
|
||||||
|
|
||||||
<IdpSignin
|
|
||||||
userId={userId}
|
|
||||||
idpIntent={idpIntent}
|
|
||||||
authRequestId={authRequestId}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</DynamicTheme>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default async function Page(props: {
|
export default async function Page(props: {
|
||||||
searchParams: Promise<Record<string | number | symbol, string | undefined>>;
|
searchParams: Promise<Record<string | number | symbol, string | undefined>>;
|
||||||
params: Promise<{ provider: string }>;
|
params: Promise<{ provider: string }>;
|
||||||
@@ -139,6 +72,39 @@ export default async function Page(props: {
|
|||||||
|
|
||||||
const providerType = idpTypeToIdentityProviderType(idp.type);
|
const providerType = idpTypeToIdentityProviderType(idp.type);
|
||||||
|
|
||||||
|
if (link) {
|
||||||
|
if (!options?.isLinkingAllowed) {
|
||||||
|
// linking was probably disallowed since the invitation was created
|
||||||
|
return linkingFailed(branding, "Linking is no longer allowed");
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
|
return linkingFailed(branding);
|
||||||
|
} else {
|
||||||
|
return linkingSuccess(
|
||||||
|
userId,
|
||||||
|
{ idpIntentId: id, idpIntentToken: token },
|
||||||
|
authRequestId,
|
||||||
|
branding,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// search for potential user via username, then link
|
// search for potential user via username, then link
|
||||||
if (options?.isLinkingAllowed) {
|
if (options?.isLinkingAllowed) {
|
||||||
let foundUser;
|
let foundUser;
|
||||||
@@ -166,31 +132,24 @@ export default async function Page(props: {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (foundUser) {
|
if (foundUser) {
|
||||||
const idpLink = await addIDPLink(
|
let idpLink;
|
||||||
|
try {
|
||||||
|
idpLink = await addIDPLink(
|
||||||
{
|
{
|
||||||
id: idpInformation.idpId,
|
id: idpInformation.idpId,
|
||||||
userId: idpInformation.userId,
|
userId: idpInformation.userId,
|
||||||
userName: idpInformation.userName,
|
userName: idpInformation.userName,
|
||||||
},
|
},
|
||||||
foundUser.userId,
|
foundUser.userId,
|
||||||
).catch((error) => {
|
|
||||||
return (
|
|
||||||
<DynamicTheme branding={branding}>
|
|
||||||
<div className="flex flex-col items-center space-y-4">
|
|
||||||
<h1>{t("linkingError.title")}</h1>
|
|
||||||
<div className="w-full">
|
|
||||||
{
|
|
||||||
<Alert type={AlertType.ALERT}>
|
|
||||||
{t("linkingError.description")}
|
|
||||||
</Alert>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</DynamicTheme>
|
|
||||||
);
|
);
|
||||||
});
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
return linkingFailed(branding);
|
||||||
|
}
|
||||||
|
|
||||||
if (idpLink) {
|
if (!idpLink) {
|
||||||
|
return linkingFailed(branding);
|
||||||
|
} else {
|
||||||
return linkingSuccess(
|
return linkingSuccess(
|
||||||
foundUser.userId,
|
foundUser.userId,
|
||||||
{ idpIntentId: id, idpIntentToken: token },
|
{ idpIntentId: id, idpIntentToken: token },
|
||||||
|
26
apps/login/src/components/idps/pages/linking-failed.tsx
Normal file
26
apps/login/src/components/idps/pages/linking-failed.tsx
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
import { BrandingSettings } from "@zitadel/proto/zitadel/settings/v2/branding_settings_pb";
|
||||||
|
import { getLocale, getTranslations } from "next-intl/server";
|
||||||
|
import { Alert, AlertType } from "../../alert";
|
||||||
|
import { DynamicTheme } from "../../dynamic-theme";
|
||||||
|
|
||||||
|
export async function linkingFailed(
|
||||||
|
branding?: BrandingSettings,
|
||||||
|
error?: string,
|
||||||
|
) {
|
||||||
|
const locale = getLocale();
|
||||||
|
const t = await getTranslations({ locale, namespace: "idp" });
|
||||||
|
|
||||||
|
return (
|
||||||
|
<DynamicTheme branding={branding}>
|
||||||
|
<div className="flex flex-col items-center space-y-4">
|
||||||
|
<h1>{t("linkingError.title")}</h1>
|
||||||
|
<p className="ztdl-p">{t("linkingError.description")}</p>
|
||||||
|
{error && (
|
||||||
|
<div className="w-full">
|
||||||
|
{<Alert type={AlertType.ALERT}>{error}</Alert>}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</DynamicTheme>
|
||||||
|
);
|
||||||
|
}
|
29
apps/login/src/components/idps/pages/linking-success.tsx
Normal file
29
apps/login/src/components/idps/pages/linking-success.tsx
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
import { BrandingSettings } from "@zitadel/proto/zitadel/settings/v2/branding_settings_pb";
|
||||||
|
import { getLocale, getTranslations } from "next-intl/server";
|
||||||
|
import { DynamicTheme } from "../../dynamic-theme";
|
||||||
|
import { IdpSignin } from "../../idp-signin";
|
||||||
|
|
||||||
|
export 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 (
|
||||||
|
<DynamicTheme branding={branding}>
|
||||||
|
<div className="flex flex-col items-center space-y-4">
|
||||||
|
<h1>{t("linkingSuccess.title")}</h1>
|
||||||
|
<p className="ztdl-p">{t("linkingSuccess.description")}</p>
|
||||||
|
|
||||||
|
<IdpSignin
|
||||||
|
userId={userId}
|
||||||
|
idpIntent={idpIntent}
|
||||||
|
authRequestId={authRequestId}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</DynamicTheme>
|
||||||
|
);
|
||||||
|
}
|
23
apps/login/src/components/idps/pages/login-failed.tsx
Normal file
23
apps/login/src/components/idps/pages/login-failed.tsx
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
import { BrandingSettings } from "@zitadel/proto/zitadel/settings/v2/branding_settings_pb";
|
||||||
|
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) {
|
||||||
|
const locale = getLocale();
|
||||||
|
const t = await getTranslations({ locale, namespace: "idp" });
|
||||||
|
|
||||||
|
return (
|
||||||
|
<DynamicTheme branding={branding}>
|
||||||
|
<div className="flex flex-col items-center space-y-4">
|
||||||
|
<h1>{t("loginError.title")}</h1>
|
||||||
|
<p className="ztdl-p">{t("loginError.description")}</p>
|
||||||
|
{error && (
|
||||||
|
<div className="w-full">
|
||||||
|
{<Alert type={AlertType.ALERT}>{error}</Alert>}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</DynamicTheme>
|
||||||
|
);
|
||||||
|
}
|
29
apps/login/src/components/idps/pages/login-success.tsx
Normal file
29
apps/login/src/components/idps/pages/login-success.tsx
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
import { BrandingSettings } from "@zitadel/proto/zitadel/settings/v2/branding_settings_pb";
|
||||||
|
import { getLocale, getTranslations } from "next-intl/server";
|
||||||
|
import { DynamicTheme } from "../../dynamic-theme";
|
||||||
|
import { IdpSignin } from "../../idp-signin";
|
||||||
|
|
||||||
|
export 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 (
|
||||||
|
<DynamicTheme branding={branding}>
|
||||||
|
<div className="flex flex-col items-center space-y-4">
|
||||||
|
<h1>{t("loginSuccess.title")}</h1>
|
||||||
|
<p className="ztdl-p">{t("loginSuccess.description")}</p>
|
||||||
|
|
||||||
|
<IdpSignin
|
||||||
|
userId={userId}
|
||||||
|
idpIntent={idpIntent}
|
||||||
|
authRequestId={authRequestId}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</DynamicTheme>
|
||||||
|
);
|
||||||
|
}
|
@@ -70,11 +70,7 @@ export function SignInWithIdp({
|
|||||||
const renderIDPButton = (idp: IdentityProvider) => {
|
const renderIDPButton = (idp: IdentityProvider) => {
|
||||||
const { id, name, type } = idp;
|
const { id, name, type } = idp;
|
||||||
const onClick = () => startFlow(id, idpTypeToSlug(type));
|
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<
|
const components: Partial<
|
||||||
Record<
|
Record<
|
||||||
IdentityProviderType,
|
IdentityProviderType,
|
||||||
|
@@ -120,6 +120,7 @@ export async function sendVerificationRedirectWithoutCheck(command: {
|
|||||||
if (!authMethodResponse || !authMethodResponse.authMethodTypes) {
|
if (!authMethodResponse || !authMethodResponse.authMethodTypes) {
|
||||||
return { error: "Could not load possible authenticators" };
|
return { error: "Could not load possible authenticators" };
|
||||||
}
|
}
|
||||||
|
|
||||||
// if no authmethods are found on the user, redirect to set one up
|
// if no authmethods are found on the user, redirect to set one up
|
||||||
if (
|
if (
|
||||||
authMethodResponse &&
|
authMethodResponse &&
|
||||||
|
@@ -633,11 +633,15 @@ export async function verifyU2FRegistration(
|
|||||||
return userService.verifyU2FRegistration(request, {});
|
return userService.verifyU2FRegistration(request, {});
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getActiveIdentityProviders(orgId?: string) {
|
export async function getActiveIdentityProviders(
|
||||||
return settingsService.getActiveIdentityProviders(
|
orgId?: string,
|
||||||
{ ctx: makeReqCtx(orgId) },
|
linking_allowed?: boolean,
|
||||||
{},
|
) {
|
||||||
);
|
const props: any = { ctx: makeReqCtx(orgId) };
|
||||||
|
if (linking_allowed) {
|
||||||
|
props.linkingAllowed = linking_allowed;
|
||||||
|
}
|
||||||
|
return settingsService.getActiveIdentityProviders(props, {});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Reference in New Issue
Block a user