fix: cleanup start idp flow

This commit is contained in:
Max Peintner
2025-07-01 10:59:43 +02:00
parent f7e272ace2
commit 00e2bddc60
4 changed files with 58 additions and 44 deletions

View File

@@ -25,7 +25,6 @@ import {
import { CreateResponseRequestSchema } from "@zitadel/proto/zitadel/saml/v2/saml_service_pb"; import { CreateResponseRequestSchema } from "@zitadel/proto/zitadel/saml/v2/saml_service_pb";
import { Session } from "@zitadel/proto/zitadel/session/v2/session_pb"; import { Session } from "@zitadel/proto/zitadel/session/v2/session_pb";
import { IdentityProviderType } from "@zitadel/proto/zitadel/settings/v2/login_settings_pb"; import { IdentityProviderType } from "@zitadel/proto/zitadel/settings/v2/login_settings_pb";
import { FormData } from "@zitadel/proto/zitadel/user/v2/idp_pb";
import { headers } from "next/headers"; import { headers } from "next/headers";
import { NextRequest, NextResponse } from "next/server"; import { NextRequest, NextResponse } from "next/server";
import { DEFAULT_CSP } from "../../../constants/csp"; import { DEFAULT_CSP } from "../../../constants/csp";
@@ -218,7 +217,7 @@ export async function GET(request: NextRequest) {
params.set("organization", organization); params.set("organization", organization);
} }
return startIdentityProviderFlow({ const url = await startIdentityProviderFlow({
serviceUrl, serviceUrl,
idpId, idpId,
urls: { urls: {
@@ -229,25 +228,18 @@ export async function GET(request: NextRequest) {
`${origin}/idp/${provider}/failure?` + `${origin}/idp/${provider}/failure?` +
new URLSearchParams(params), new URLSearchParams(params),
}, },
}).then((resp) => {
if (resp.nextStep.case === "authUrl" && resp.nextStep.value) {
return NextResponse.redirect(resp.nextStep.value);
} else if (
resp.nextStep.case === "formData" &&
resp.nextStep.value
) {
const formData: FormData = resp.nextStep.value;
const redirectUrl = constructUrl(request, "/saml-post");
redirectUrl.searchParams.set("url", formData.url);
Object.entries(formData.fields).forEach(([k, v]) => {
redirectUrl.searchParams.set(k, v);
}); });
return NextResponse.redirect(redirectUrl.toString()); if (!url) {
return NextResponse.json(
{ error: "Could not start IDP flow" },
{ status: 500 },
);
} }
});
const absoluteUrl = constructUrl(request, url);
return NextResponse.redirect(absoluteUrl);
} }
} }
} }

View File

@@ -74,22 +74,20 @@ export type StartIDPFlowCommand = {
async function startIDPFlow(command: StartIDPFlowCommand) { async function startIDPFlow(command: StartIDPFlowCommand) {
const basePath = process.env.NEXT_PUBLIC_BASE_PATH ?? ""; const basePath = process.env.NEXT_PUBLIC_BASE_PATH ?? "";
return startIdentityProviderFlow({ const url = await startIdentityProviderFlow({
serviceUrl: command.serviceUrl, serviceUrl: command.serviceUrl,
idpId: command.idpId, idpId: command.idpId,
urls: { urls: {
successUrl: `${command.host.includes("localhost") ? "http://" : "https://"}${command.host}${basePath}${command.successUrl}`, successUrl: `${command.host.includes("localhost") ? "http://" : "https://"}${command.host}${basePath}${command.successUrl}`,
failureUrl: `${command.host.includes("localhost") ? "http://" : "https://"}${command.host}${basePath}${command.failureUrl}`, failureUrl: `${command.host.includes("localhost") ? "http://" : "https://"}${command.host}${basePath}${command.failureUrl}`,
}, },
}).then((response) => {
if (
response &&
response.nextStep.case === "authUrl" &&
response?.nextStep.value
) {
return { redirect: response.nextStep.value };
}
}); });
if (!url) {
return { error: "Could not start IDP flow" };
}
return { redirect: url };
} }
type CreateNewSessionCommand = { type CreateNewSessionCommand = {

View File

@@ -102,7 +102,7 @@ export async function sendLoginname(command: SendLoginnameCommand) {
const basePath = process.env.NEXT_PUBLIC_BASE_PATH ?? ""; const basePath = process.env.NEXT_PUBLIC_BASE_PATH ?? "";
const resp = await startIdentityProviderFlow({ const url = await startIdentityProviderFlow({
serviceUrl, serviceUrl,
idpId: identityProviders[0].id, idpId: identityProviders[0].id,
urls: { urls: {
@@ -115,9 +115,11 @@ export async function sendLoginname(command: SendLoginnameCommand) {
}, },
}); });
if (resp?.nextStep.case === "authUrl") { if (!url) {
return { redirect: resp.nextStep.value }; return { error: "Could not start IDP flow" };
} }
return { redirect: url };
} }
}; };
@@ -166,7 +168,7 @@ export async function sendLoginname(command: SendLoginnameCommand) {
const basePath = process.env.NEXT_PUBLIC_BASE_PATH ?? ""; const basePath = process.env.NEXT_PUBLIC_BASE_PATH ?? "";
const resp = await startIdentityProviderFlow({ const url = await startIdentityProviderFlow({
serviceUrl, serviceUrl,
idpId: idp.id, idpId: idp.id,
urls: { urls: {
@@ -179,9 +181,11 @@ export async function sendLoginname(command: SendLoginnameCommand) {
}, },
}); });
if (resp?.nextStep.case === "authUrl") { if (!url) {
return { redirect: resp.nextStep.value }; return { error: "Could not start IDP flow" };
} }
return { redirect: url };
} }
}; };

View File

@@ -23,7 +23,10 @@ import {
import { LoginSettings } from "@zitadel/proto/zitadel/settings/v2/login_settings_pb"; import { LoginSettings } from "@zitadel/proto/zitadel/settings/v2/login_settings_pb";
import { SettingsService } from "@zitadel/proto/zitadel/settings/v2/settings_service_pb"; import { SettingsService } from "@zitadel/proto/zitadel/settings/v2/settings_service_pb";
import { SendEmailVerificationCodeSchema } from "@zitadel/proto/zitadel/user/v2/email_pb"; import { SendEmailVerificationCodeSchema } from "@zitadel/proto/zitadel/user/v2/email_pb";
import type { RedirectURLsJson } from "@zitadel/proto/zitadel/user/v2/idp_pb"; import type {
FormData,
RedirectURLsJson,
} from "@zitadel/proto/zitadel/user/v2/idp_pb";
import { import {
NotificationType, NotificationType,
SendPasswordResetLinkSchema, SendPasswordResetLinkSchema,
@@ -964,18 +967,35 @@ export async function startIdentityProviderFlow({
serviceUrl: string; serviceUrl: string;
idpId: string; idpId: string;
urls: RedirectURLsJson; urls: RedirectURLsJson;
}) { }): Promise<string | null> {
const userService: Client<typeof UserService> = await createServiceForHost( const userService: Client<typeof UserService> = await createServiceForHost(
UserService, UserService,
serviceUrl, serviceUrl,
); );
return userService.startIdentityProviderIntent({ return userService
.startIdentityProviderIntent({
idpId, idpId,
content: { content: {
case: "urls", case: "urls",
value: urls, value: urls,
}, },
})
.then((resp) => {
if (resp.nextStep.case === "authUrl" && resp.nextStep.value) {
return resp.nextStep.value;
} else if (resp.nextStep.case === "formData" && resp.nextStep.value) {
const formData: FormData = resp.nextStep.value;
const redirectUrl = new URL("/saml-post");
redirectUrl.searchParams.set("url", formData.url);
Object.entries(formData.fields).forEach(([k, v]) => {
redirectUrl.searchParams.set(k, v);
});
return redirectUrl.toString();
}
return null;
}); });
} }