mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-14 03:27:34 +00:00
@@ -1,15 +1,15 @@
|
|||||||
import { Cookie, getAllSessions } from "@/lib/cookies";
|
import { getAllSessions } from "@/lib/cookies";
|
||||||
import { idpTypeToSlug } from "@/lib/idp";
|
import { idpTypeToSlug } from "@/lib/idp";
|
||||||
|
import { loginWithOIDCandSession } from "@/lib/oidc";
|
||||||
import { loginWithSAMLandSession } from "@/lib/saml";
|
import { loginWithSAMLandSession } from "@/lib/saml";
|
||||||
import { sendLoginname, SendLoginnameCommand } from "@/lib/server/loginname";
|
import { sendLoginname, SendLoginnameCommand } from "@/lib/server/loginname";
|
||||||
import { getServiceUrlFromHeaders } from "@/lib/service";
|
import { getServiceUrlFromHeaders } from "@/lib/service";
|
||||||
import { findValidSession, isSessionValid } from "@/lib/session";
|
import { findValidSession } from "@/lib/session";
|
||||||
import {
|
import {
|
||||||
createCallback,
|
createCallback,
|
||||||
createResponse,
|
createResponse,
|
||||||
getActiveIdentityProviders,
|
getActiveIdentityProviders,
|
||||||
getAuthRequest,
|
getAuthRequest,
|
||||||
getLoginSettings,
|
|
||||||
getOrgsByDomain,
|
getOrgsByDomain,
|
||||||
getSAMLRequest,
|
getSAMLRequest,
|
||||||
listSessions,
|
listSessions,
|
||||||
@@ -528,124 +528,3 @@ export async function GET(request: NextRequest) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type LoginWithOIDCandSession = {
|
|
||||||
serviceUrl: string;
|
|
||||||
authRequest: string;
|
|
||||||
sessionId: string;
|
|
||||||
sessions: Session[];
|
|
||||||
sessionCookies: Cookie[];
|
|
||||||
request: NextRequest;
|
|
||||||
};
|
|
||||||
|
|
||||||
export async function loginWithOIDCandSession({
|
|
||||||
serviceUrl,
|
|
||||||
authRequest,
|
|
||||||
sessionId,
|
|
||||||
sessions,
|
|
||||||
sessionCookies,
|
|
||||||
request,
|
|
||||||
}: LoginWithOIDCandSession) {
|
|
||||||
console.log(
|
|
||||||
`Login with session: ${sessionId} and authRequest: ${authRequest}`,
|
|
||||||
);
|
|
||||||
|
|
||||||
const selectedSession = sessions.find((s) => s.id === sessionId);
|
|
||||||
|
|
||||||
if (selectedSession && selectedSession.id) {
|
|
||||||
console.log(`Found session ${selectedSession.id}`);
|
|
||||||
|
|
||||||
const isValid = await isSessionValid({
|
|
||||||
serviceUrl,
|
|
||||||
session: selectedSession,
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log("Session is valid:", isValid);
|
|
||||||
|
|
||||||
if (!isValid && selectedSession.factors?.user) {
|
|
||||||
// if the session is not valid anymore, we need to redirect the user to re-authenticate /
|
|
||||||
// TODO: handle IDP intent direcly if available
|
|
||||||
const command: SendLoginnameCommand = {
|
|
||||||
loginName: selectedSession.factors.user?.loginName,
|
|
||||||
organization: selectedSession.factors?.user?.organizationId,
|
|
||||||
requestId: `oidc_${authRequest}`,
|
|
||||||
};
|
|
||||||
|
|
||||||
const res = await sendLoginname(command);
|
|
||||||
|
|
||||||
if (res && "redirect" in res && res?.redirect) {
|
|
||||||
const absoluteUrl = new URL(res.redirect, request.url);
|
|
||||||
return NextResponse.redirect(absoluteUrl.toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const cookie = sessionCookies.find(
|
|
||||||
(cookie) => cookie.id === selectedSession?.id,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (cookie && cookie.id && cookie.token) {
|
|
||||||
const session = {
|
|
||||||
sessionId: cookie?.id,
|
|
||||||
sessionToken: cookie?.token,
|
|
||||||
};
|
|
||||||
|
|
||||||
// works not with _rsc request
|
|
||||||
try {
|
|
||||||
const { callbackUrl } = await createCallback({
|
|
||||||
serviceUrl,
|
|
||||||
req: create(CreateCallbackRequestSchema, {
|
|
||||||
authRequestId: authRequest,
|
|
||||||
callbackKind: {
|
|
||||||
case: "session",
|
|
||||||
value: create(SessionSchema, session),
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
if (callbackUrl) {
|
|
||||||
return NextResponse.redirect(callbackUrl);
|
|
||||||
} else {
|
|
||||||
return NextResponse.json(
|
|
||||||
{ error: "An error occurred!" },
|
|
||||||
{ status: 500 },
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} catch (error: unknown) {
|
|
||||||
// handle already handled gracefully as these could come up if old emails with requestId are used (reset password, register emails etc.)
|
|
||||||
console.error(error);
|
|
||||||
if (
|
|
||||||
error &&
|
|
||||||
typeof error === "object" &&
|
|
||||||
"code" in error &&
|
|
||||||
error?.code === 9
|
|
||||||
) {
|
|
||||||
const loginSettings = await getLoginSettings({
|
|
||||||
serviceUrl,
|
|
||||||
organization: selectedSession.factors?.user?.organizationId,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (loginSettings?.defaultRedirectUri) {
|
|
||||||
return NextResponse.redirect(loginSettings.defaultRedirectUri);
|
|
||||||
}
|
|
||||||
|
|
||||||
const signedinUrl = new URL("/signedin", request.url);
|
|
||||||
|
|
||||||
if (selectedSession.factors?.user?.loginName) {
|
|
||||||
signedinUrl.searchParams.set(
|
|
||||||
"loginName",
|
|
||||||
selectedSession.factors?.user?.loginName,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (selectedSession.factors?.user?.organizationId) {
|
|
||||||
signedinUrl.searchParams.set(
|
|
||||||
"organization",
|
|
||||||
selectedSession.factors?.user?.organizationId,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return NextResponse.redirect(signedinUrl);
|
|
||||||
} else {
|
|
||||||
return NextResponse.json({ error }, { status: 500 });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
131
apps/login/src/lib/oidc.ts
Normal file
131
apps/login/src/lib/oidc.ts
Normal file
@@ -0,0 +1,131 @@
|
|||||||
|
import { Cookie } from "@/lib/cookies";
|
||||||
|
import { sendLoginname, SendLoginnameCommand } from "@/lib/server/loginname";
|
||||||
|
import { createCallback, getLoginSettings } from "@/lib/zitadel";
|
||||||
|
import { create } from "@zitadel/client";
|
||||||
|
import {
|
||||||
|
CreateCallbackRequestSchema,
|
||||||
|
SessionSchema,
|
||||||
|
} from "@zitadel/proto/zitadel/oidc/v2/oidc_service_pb";
|
||||||
|
import { Session } from "@zitadel/proto/zitadel/session/v2/session_pb";
|
||||||
|
import { NextRequest, NextResponse } from "next/server";
|
||||||
|
import { isSessionValid } from "./session";
|
||||||
|
|
||||||
|
type LoginWithOIDCandSession = {
|
||||||
|
serviceUrl: string;
|
||||||
|
authRequest: string;
|
||||||
|
sessionId: string;
|
||||||
|
sessions: Session[];
|
||||||
|
sessionCookies: Cookie[];
|
||||||
|
request: NextRequest;
|
||||||
|
};
|
||||||
|
export async function loginWithOIDCandSession({
|
||||||
|
serviceUrl,
|
||||||
|
authRequest,
|
||||||
|
sessionId,
|
||||||
|
sessions,
|
||||||
|
sessionCookies,
|
||||||
|
request,
|
||||||
|
}: LoginWithOIDCandSession) {
|
||||||
|
console.log(
|
||||||
|
`Login with session: ${sessionId} and authRequest: ${authRequest}`,
|
||||||
|
);
|
||||||
|
|
||||||
|
const selectedSession = sessions.find((s) => s.id === sessionId);
|
||||||
|
|
||||||
|
if (selectedSession && selectedSession.id) {
|
||||||
|
console.log(`Found session ${selectedSession.id}`);
|
||||||
|
|
||||||
|
const isValid = await isSessionValid({
|
||||||
|
serviceUrl,
|
||||||
|
session: selectedSession,
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log("Session is valid:", isValid);
|
||||||
|
|
||||||
|
if (!isValid && selectedSession.factors?.user) {
|
||||||
|
// if the session is not valid anymore, we need to redirect the user to re-authenticate /
|
||||||
|
// TODO: handle IDP intent direcly if available
|
||||||
|
const command: SendLoginnameCommand = {
|
||||||
|
loginName: selectedSession.factors.user?.loginName,
|
||||||
|
organization: selectedSession.factors?.user?.organizationId,
|
||||||
|
requestId: `oidc_${authRequest}`,
|
||||||
|
};
|
||||||
|
|
||||||
|
const res = await sendLoginname(command);
|
||||||
|
|
||||||
|
if (res && "redirect" in res && res?.redirect) {
|
||||||
|
const absoluteUrl = new URL(res.redirect, request.url);
|
||||||
|
return NextResponse.redirect(absoluteUrl.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const cookie = sessionCookies.find(
|
||||||
|
(cookie) => cookie.id === selectedSession?.id,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (cookie && cookie.id && cookie.token) {
|
||||||
|
const session = {
|
||||||
|
sessionId: cookie?.id,
|
||||||
|
sessionToken: cookie?.token,
|
||||||
|
};
|
||||||
|
|
||||||
|
// works not with _rsc request
|
||||||
|
try {
|
||||||
|
const { callbackUrl } = await createCallback({
|
||||||
|
serviceUrl,
|
||||||
|
req: create(CreateCallbackRequestSchema, {
|
||||||
|
authRequestId: authRequest,
|
||||||
|
callbackKind: {
|
||||||
|
case: "session",
|
||||||
|
value: create(SessionSchema, session),
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
if (callbackUrl) {
|
||||||
|
return NextResponse.redirect(callbackUrl);
|
||||||
|
} else {
|
||||||
|
return NextResponse.json(
|
||||||
|
{ error: "An error occurred!" },
|
||||||
|
{ status: 500 },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} catch (error: unknown) {
|
||||||
|
// handle already handled gracefully as these could come up if old emails with requestId are used (reset password, register emails etc.)
|
||||||
|
console.error(error);
|
||||||
|
if (
|
||||||
|
error &&
|
||||||
|
typeof error === "object" &&
|
||||||
|
"code" in error &&
|
||||||
|
error?.code === 9
|
||||||
|
) {
|
||||||
|
const loginSettings = await getLoginSettings({
|
||||||
|
serviceUrl,
|
||||||
|
organization: selectedSession.factors?.user?.organizationId,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (loginSettings?.defaultRedirectUri) {
|
||||||
|
return NextResponse.redirect(loginSettings.defaultRedirectUri);
|
||||||
|
}
|
||||||
|
|
||||||
|
const signedinUrl = new URL("/signedin", request.url);
|
||||||
|
|
||||||
|
if (selectedSession.factors?.user?.loginName) {
|
||||||
|
signedinUrl.searchParams.set(
|
||||||
|
"loginName",
|
||||||
|
selectedSession.factors?.user?.loginName,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (selectedSession.factors?.user?.organizationId) {
|
||||||
|
signedinUrl.searchParams.set(
|
||||||
|
"organization",
|
||||||
|
selectedSession.factors?.user?.organizationId,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return NextResponse.redirect(signedinUrl);
|
||||||
|
} else {
|
||||||
|
return NextResponse.json({ error }, { status: 500 });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user