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 6ae205bcb5f..166c6b03ab8 100644 --- a/apps/login/src/app/(login)/idp/[provider]/failure/page.tsx +++ b/apps/login/src/app/(login)/idp/[provider]/failure/page.tsx @@ -1,4 +1,3 @@ -import { ProviderSlug } from "@/lib/demos"; import { getBrandingSettings, PROVIDER_NAME_MAPPING } from "@/lib/zitadel"; import DynamicTheme from "@/ui/DynamicTheme"; @@ -7,7 +6,7 @@ export default async function Page({ params, }: { searchParams: Record; - params: { provider: ProviderSlug }; + params: { provider: string }; }) { const { id, token, authRequestId, organization } = searchParams; const { provider } = params; 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 134ea2ff656..27e8f24f82a 100644 --- a/apps/login/src/app/(login)/idp/[provider]/success/page.tsx +++ b/apps/login/src/app/(login)/idp/[provider]/success/page.tsx @@ -1,4 +1,3 @@ -import { ProviderSlug } from "@/lib/demos"; import { addIDPLink, createUser, @@ -11,18 +10,14 @@ import { import Alert, { AlertType } from "@/ui/Alert"; import DynamicTheme from "@/ui/DynamicTheme"; import IdpSignin from "@/ui/IdpSignin"; -import { AddHumanUserRequest } from "@zitadel/proto/zitadel/user/v2/user_service_pb"; -import { IDPInformation, IDPLink } from "@zitadel/proto/zitadel/user/v2/idp_pb"; import { AutoLinkingOption } from "@zitadel/proto/zitadel/idp/v2/idp_pb"; -import { PartialMessage } from "@zitadel/client"; - export default async function Page({ searchParams, params, }: { searchParams: Record; - params: { provider: ProviderSlug }; + params: { provider: string }; }) { const { id, token, authRequestId, organization } = searchParams; const { provider } = params; diff --git a/apps/login/src/app/api/loginname/route.ts b/apps/login/src/app/api/loginname/route.ts index ccc8a77bbd5..b6751ae9164 100644 --- a/apps/login/src/app/api/loginname/route.ts +++ b/apps/login/src/app/api/loginname/route.ts @@ -1,4 +1,4 @@ -import { ProviderSlug } from "@/lib/demos"; +import { idpTypeToSlug } from "@/lib/idp"; import { getActiveIdentityProviders, getLoginSettings, @@ -7,14 +7,16 @@ import { startIdentityProviderFlow, } from "@/lib/zitadel"; import { createSessionForUserIdAndUpdateCookie } from "@/utils/session"; -import { IdentityProviderType } from "@zitadel/proto/zitadel/settings/v2/login_settings_pb"; import { NextRequest, NextResponse } from "next/server"; export async function POST(request: NextRequest) { const body = await request.json(); if (body) { const { loginName, authRequestId, organization } = body; - return listUsers(loginName, organization).then(async (users) => { + return listUsers({ + userName: loginName, + organizationId: organization, + }).then(async (users) => { if (users.details?.totalResult == BigInt(1) && users.result[0].userId) { const userId = users.result[0].userId; return createSessionForUserIdAndUpdateCookie( @@ -64,28 +66,8 @@ export async function POST(request: NextRequest) { const host = request.nextUrl.origin; const identityProviderType = identityProviders[0].type; - let provider: string; - switch (identityProviderType) { - case IdentityProviderType.GITHUB: - provider = "github"; - break; - case IdentityProviderType.GOOGLE: - provider = "google"; - break; - case IdentityProviderType.AZURE_AD: - provider = "azure"; - break; - case IdentityProviderType.SAML: - provider = "saml"; - break; - case IdentityProviderType.OIDC: - provider = "oidc"; - break; - default: - provider = "oidc"; - break; - } + const provider = idpTypeToSlug(identityProviderType); const params = new URLSearchParams(); diff --git a/apps/login/src/app/login/route.ts b/apps/login/src/app/login/route.ts index 80b3bed72a8..85eae70ee0c 100644 --- a/apps/login/src/app/login/route.ts +++ b/apps/login/src/app/login/route.ts @@ -18,6 +18,7 @@ import { Prompt, } from "@zitadel/proto/zitadel/oidc/v2/authorization_pb"; import { IdentityProviderType } from "@zitadel/proto/zitadel/settings/v2/login_settings_pb"; +import { idpTypeToSlug } from "@/lib/idp"; async function loadSessions(ids: string[]): Promise { const response = await listSessions( @@ -168,28 +169,7 @@ export async function GET(request: NextRequest) { const host = request.nextUrl.origin; const identityProviderType = identityProviders[0].type; - let provider: string; - - switch (identityProviderType) { - case IdentityProviderType.GITHUB: - provider = "github"; - break; - case IdentityProviderType.GOOGLE: - provider = "google"; - break; - case IdentityProviderType.AZURE_AD: - provider = "azure"; - break; - case IdentityProviderType.SAML: - provider = "saml"; - break; - case IdentityProviderType.OIDC: - provider = "oidc"; - break; - default: - provider = "oidc"; - break; - } + let provider = idpTypeToSlug(identityProviderType); const params = new URLSearchParams(); diff --git a/apps/login/src/lib/demos.ts b/apps/login/src/lib/demos.ts index 13e2a3017a8..38912e50e5a 100644 --- a/apps/login/src/lib/demos.ts +++ b/apps/login/src/lib/demos.ts @@ -4,12 +4,6 @@ export type Item = { description?: string; }; -export enum ProviderSlug { - GOOGLE = "google", - GITHUB = "github", - AZURE = "microsoft", -} - export const demos: { name: string; items: Item[] }[] = [ { name: "Login", diff --git a/apps/login/src/lib/idp.ts b/apps/login/src/lib/idp.ts new file mode 100644 index 00000000000..408dab73c4c --- /dev/null +++ b/apps/login/src/lib/idp.ts @@ -0,0 +1,125 @@ +import { AddHumanUserRequest } from "@zitadel/proto/zitadel/user/v2/user_service_pb"; +import { IDPInformation, IDPLink } from "@zitadel/proto/zitadel/user/v2/idp_pb"; +import { IdentityProviderType } from "@zitadel/proto/zitadel/settings/v2/login_settings_pb"; +import { PartialMessage } from "@zitadel/client"; + +export function idpTypeToSlug(idpType: IdentityProviderType) { + switch (idpType) { + case IdentityProviderType.GITHUB: + return "github"; + case IdentityProviderType.GOOGLE: + return "google"; + case IdentityProviderType.AZURE_AD: + return "azure"; + case IdentityProviderType.SAML: + return "saml"; + case IdentityProviderType.OIDC: + return "oidc"; + default: + throw new Error("Unknown identity provider type"); + } +} + +export const PROVIDER_NAME_MAPPING: { + [provider: string]: string; +} = { + [IdentityProviderType.GOOGLE]: "Google", + [IdentityProviderType.GITHUB]: "GitHub", + [IdentityProviderType.AZURE_AD]: "Microsoft", +}; + +export const PROVIDER_MAPPING: { + [provider: string]: ( + rI: IDPInformation, + ) => PartialMessage; +} = { + [IdentityProviderType.GOOGLE]: (idp: IDPInformation) => { + const rawInfo = idp.rawInformation?.toJson() as { + User: { + email: string; + name?: string; + given_name?: string; + family_name?: string; + }; + }; + + const idpLink: PartialMessage = { + idpId: idp.idpId, + userId: idp.userId, + userName: idp.userName, + }; + + const req: PartialMessage = { + username: idp.userName, + email: { + email: rawInfo.User?.email, + verification: { case: "isVerified", value: true }, + }, + // organisation: Organisation | undefined; + profile: { + displayName: rawInfo.User?.name ?? "", + givenName: rawInfo.User?.given_name ?? "", + familyName: rawInfo.User?.family_name ?? "", + }, + idpLinks: [idpLink], + }; + return req; + }, + [IdentityProviderType.AZURE_AD]: (idp: IDPInformation) => { + const rawInfo = idp.rawInformation?.toJson() as { + mail: string; + displayName?: string; + givenName?: string; + surname?: string; + }; + + const idpLink: PartialMessage = { + idpId: idp.idpId, + userId: idp.userId, + userName: idp.userName, + }; + + const req: PartialMessage = { + username: idp.userName, + email: { + email: rawInfo?.mail, + verification: { case: "isVerified", value: true }, + }, + // organisation: Organisation | undefined; + profile: { + displayName: rawInfo?.displayName ?? "", + givenName: rawInfo?.givenName ?? "", + familyName: rawInfo?.surname ?? "", + }, + idpLinks: [idpLink], + }; + + return req; + }, + [IdentityProviderType.GITHUB]: (idp: IDPInformation) => { + const rawInfo = idp.rawInformation?.toJson() as { + email: string; + name: string; + }; + const idpLink: PartialMessage = { + idpId: idp.idpId, + userId: idp.userId, + userName: idp.userName, + }; + const req: PartialMessage = { + username: idp.userName, + email: { + email: rawInfo?.email, + verification: { case: "isVerified", value: true }, + }, + // organisation: Organisation | undefined; + profile: { + displayName: rawInfo?.name ?? "", + givenName: rawInfo?.name ?? "", + familyName: rawInfo?.name ?? "", + }, + idpLinks: [idpLink], + }; + return req; + }, +}; diff --git a/apps/login/src/lib/zitadel.ts b/apps/login/src/lib/zitadel.ts index 59dbfde29f9..7c721f345f7 100644 --- a/apps/login/src/lib/zitadel.ts +++ b/apps/login/src/lib/zitadel.ts @@ -13,17 +13,16 @@ import { RequestChallenges } from "@zitadel/proto/zitadel/session/v2/challenge_p import { RetrieveIdentityProviderIntentRequest, VerifyU2FRegistrationRequest, - AddHumanUserRequest, } from "@zitadel/proto/zitadel/user/v2/user_service_pb"; -import { IDPInformation, IDPLink } from "@zitadel/proto/zitadel/user/v2/idp_pb"; +import { IDPInformation } from "@zitadel/proto/zitadel/user/v2/idp_pb"; import { CreateCallbackRequest } from "@zitadel/proto/zitadel/oidc/v2/oidc_service_pb"; import { TextQueryMethod } from "@zitadel/proto/zitadel/object/v2/object_pb"; import type { RedirectURLs } from "@zitadel/proto/zitadel/user/v2/idp_pb"; -import { ProviderSlug } from "./demos"; import { PartialMessage, PlainMessage } from "@zitadel/client"; -import VerifyEmailForm from "@/ui/VerifyEmailForm"; import { SearchQuery as UserSearchQuery } from "@zitadel/proto/zitadel/user/v2/query_pb"; +import { IdentityProviderType } from "@zitadel/proto/zitadel/settings/v2/login_settings_pb"; +import { PROVIDER_MAPPING } from "./idp"; const SESSION_LIFETIME_S = 3000; @@ -296,14 +295,6 @@ export async function getOrgByDomain(domain: string) { return managementService.getOrgByDomainGlobal({ domain }, {}); } -export const PROVIDER_NAME_MAPPING: { - [provider: string]: string; -} = { - [ProviderSlug.GOOGLE]: "Google", - [ProviderSlug.GITHUB]: "GitHub", - [ProviderSlug.AZURE]: "Microft", -}; - export async function startIdentityProviderFlow({ idpId, urls, @@ -400,104 +391,8 @@ export function addIDPLink( ); } -export const PROVIDER_MAPPING: { - [provider: string]: ( - rI: IDPInformation, - ) => PartialMessage; -} = { - [ProviderSlug.GOOGLE]: (idp: IDPInformation) => { - const rawInfo = idp.rawInformation?.toJson() as { - User: { - email: string; - name?: string; - given_name?: string; - family_name?: string; - }; - }; - - const idpLink: PartialMessage = { - idpId: idp.idpId, - userId: idp.userId, - userName: idp.userName, - }; - - const req: PartialMessage = { - username: idp.userName, - email: { - email: rawInfo.User?.email, - verification: { case: "isVerified", value: true }, - }, - // organisation: Organisation | undefined; - profile: { - displayName: rawInfo.User?.name ?? "", - givenName: rawInfo.User?.given_name ?? "", - familyName: rawInfo.User?.family_name ?? "", - }, - idpLinks: [idpLink], - }; - return req; - }, - [ProviderSlug.AZURE]: (idp: IDPInformation) => { - const rawInfo = idp.rawInformation?.toJson() as { - mail: string; - displayName?: string; - givenName?: string; - surname?: string; - }; - - const idpLink: PartialMessage = { - idpId: idp.idpId, - userId: idp.userId, - userName: idp.userName, - }; - - const req: PartialMessage = { - username: idp.userName, - email: { - email: rawInfo?.mail, - verification: { case: "isVerified", value: true }, - }, - // organisation: Organisation | undefined; - profile: { - displayName: rawInfo?.displayName ?? "", - givenName: rawInfo?.givenName ?? "", - familyName: rawInfo?.surname ?? "", - }, - idpLinks: [idpLink], - }; - - return req; - }, - [ProviderSlug.GITHUB]: (idp: IDPInformation) => { - const rawInfo = idp.rawInformation?.toJson() as { - email: string; - name: string; - }; - const idpLink: PartialMessage = { - idpId: idp.idpId, - userId: idp.userId, - userName: idp.userName, - }; - const req: PartialMessage = { - username: idp.userName, - email: { - email: rawInfo?.email, - verification: { case: "isVerified", value: true }, - }, - // organisation: Organisation | undefined; - profile: { - displayName: rawInfo?.name ?? "", - givenName: rawInfo?.name ?? "", - familyName: rawInfo?.name ?? "", - }, - idpLinks: [idpLink], - }; - return req; - }, -}; - export function createUser( - provider: ProviderSlug, + provider: string, info: IDPInformation, ): Promise { const userData = PROVIDER_MAPPING[provider](info); diff --git a/apps/login/src/ui/SignInWithIDP.tsx b/apps/login/src/ui/SignInWithIDP.tsx index dce657b9045..af82aafc5bf 100644 --- a/apps/login/src/ui/SignInWithIDP.tsx +++ b/apps/login/src/ui/SignInWithIDP.tsx @@ -1,6 +1,6 @@ "use client"; -import { ReactNode, useState } from "react"; +import { ReactNode, useState } from "react"; import { SignInWithGitlab, SignInWithAzureAD, @@ -8,10 +8,10 @@ import { SignInWithGithub, } from "@zitadel/react"; import { useRouter } from "next/navigation"; -import { ProviderSlug } from "@/lib/demos"; import Alert from "./Alert"; -import BackButton from "./BackButton"; import { IdentityProvider } from "@zitadel/proto/zitadel/settings/v2/login_settings_pb"; +import { idpTypeToSlug } from "@/lib/idp"; +import { IdentityProviderType } from "@zitadel/proto/zitadel/settings/v2/login_settings_pb"; export interface SignInWithIDPProps { children?: ReactNode; @@ -36,7 +36,7 @@ export function SignInWithIDP({ const [error, setError] = useState(""); const router = useRouter(); - async function startFlow(idpId: string, provider: ProviderSlug) { + async function startFlow(idpId: string, provider: string) { setLoading(true); const params = new URLSearchParams(); @@ -78,62 +78,65 @@ export function SignInWithIDP({ {identityProviders && identityProviders.map((idp, i) => { switch (idp.type) { - case 6: // IdentityProviderType.IDENTITY_PROVIDER_TYPE_GITHUB: + case IdentityProviderType.GITHUB: return ( - startFlow(idp.id, ProviderSlug.GITHUB).then( - ({ authUrl }) => { - router.push(authUrl); - }, - ) + startFlow( + idp.id, + idpTypeToSlug(IdentityProviderType.GITHUB), + ).then(({ authUrl }) => { + router.push(authUrl); + }) } > ); - case 7: // IdentityProviderType.IDENTITY_PROVIDER_TYPE_GITHUB_ES: + case IdentityProviderType.GITHUB_ES: return ( alert("TODO: unimplemented")} > ); - case 5: // IdentityProviderType.IDENTITY_PROVIDER_TYPE_AZURE_AD: + case IdentityProviderType.AZURE_AD: return ( - startFlow(idp.id, ProviderSlug.AZURE).then( - ({ authUrl }) => { - router.push(authUrl); - }, - ) + startFlow( + idp.id, + idpTypeToSlug(IdentityProviderType.AZURE_AD), + ).then(({ authUrl }) => { + router.push(authUrl); + }) } > ); - case 10: // IdentityProviderType.IDENTITY_PROVIDER_TYPE_GOOGLE: + case IdentityProviderType.GOOGLE: return ( - startFlow(idp.id, ProviderSlug.GOOGLE).then( - ({ authUrl }) => { - router.push(authUrl); - }, - ) + startFlow( + idp.id, + idpTypeToSlug(IdentityProviderType.GOOGLE), + ).then(({ authUrl }) => { + router.push(authUrl); + }) } > ); - case 8: // IdentityProviderType.IDENTITY_PROVIDER_TYPE_GITLAB: + case IdentityProviderType.GITLAB: return ( alert("TODO: unimplemented")} > ); - case 9: //IdentityProviderType.IDENTITY_PROVIDER_TYPE_GITLAB_SELF_HOSTED: + case IdentityProviderType.GITLAB_SELF_HOSTED: return (