mirror of
https://github.com/zitadel/zitadel.git
synced 2025-12-12 09:54:00 +00:00
/login route, extend session cookie for authRequestId
This commit is contained in:
@@ -1,13 +1,43 @@
|
||||
import { getAuthRequest, listSessions, server } from "#/lib/zitadel";
|
||||
import { getAllSessionIds } from "#/utils/cookies";
|
||||
import { Session } from "@zitadel/server";
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
|
||||
export async function GET(request: NextRequest) {
|
||||
return NextResponse.json({ found: true });
|
||||
async function loadSessions(): Promise<Session[]> {
|
||||
const ids: string[] = await getAllSessionIds();
|
||||
|
||||
if (ids && ids.length) {
|
||||
const response = await listSessions(
|
||||
server,
|
||||
ids.filter((id: string | undefined) => !!id)
|
||||
);
|
||||
return response?.sessions ?? [];
|
||||
} else {
|
||||
console.info("No session cookie found.");
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
export async function POST(request: NextRequest) {
|
||||
const body = await request.json();
|
||||
if (body) {
|
||||
return NextResponse.json({ found: true });
|
||||
export async function GET(request: NextRequest) {
|
||||
const searchParams = request.nextUrl.searchParams;
|
||||
const authRequestId = searchParams.get("authRequest");
|
||||
|
||||
if (authRequestId) {
|
||||
const response = await getAuthRequest(server, { authRequestId });
|
||||
const sessions = await loadSessions();
|
||||
if (sessions.length) {
|
||||
return NextResponse.json(sessions);
|
||||
} else {
|
||||
const loginNameUrl = new URL("/loginname", request.url);
|
||||
if (response.authRequest?.id) {
|
||||
loginNameUrl.searchParams.set(
|
||||
"authRequestId",
|
||||
response.authRequest?.id
|
||||
);
|
||||
}
|
||||
|
||||
return NextResponse.redirect(loginNameUrl);
|
||||
}
|
||||
} else {
|
||||
return NextResponse.error();
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ export default async function Page({
|
||||
searchParams: Record<string | number | symbol, string | undefined>;
|
||||
}) {
|
||||
const loginName = searchParams?.loginName;
|
||||
const authRequestId = searchParams?.authRequestId;
|
||||
const submit: boolean = searchParams?.submit === "true";
|
||||
|
||||
const loginSettings = await getLoginSettings(server);
|
||||
@@ -19,6 +20,7 @@ export default async function Page({
|
||||
<UsernameForm
|
||||
loginSettings={loginSettings}
|
||||
loginName={loginName}
|
||||
authRequestId={authRequestId}
|
||||
submit={submit}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -7,47 +7,53 @@ import { getSessionCookieById } from "#/utils/cookies";
|
||||
import { createSessionAndUpdateCookie } from "#/utils/session";
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
|
||||
export async function GET(request: NextRequest) {
|
||||
const { searchParams } = new URL(request.url);
|
||||
const sessionId = searchParams.get("sessionId");
|
||||
if (sessionId) {
|
||||
const sessionCookie = await getSessionCookieById(sessionId);
|
||||
// export async function GET(request: NextRequest) {
|
||||
// const { searchParams } = new URL(request.url);
|
||||
// const sessionId = searchParams.get("sessionId");
|
||||
// if (sessionId) {
|
||||
// const sessionCookie = await getSessionCookieById(sessionId);
|
||||
|
||||
const session = await getSession(
|
||||
server,
|
||||
sessionCookie.id,
|
||||
sessionCookie.token
|
||||
);
|
||||
// const session = await getSession(
|
||||
// server,
|
||||
// sessionCookie.id,
|
||||
// sessionCookie.token
|
||||
// );
|
||||
|
||||
const userId = session?.session?.factors?.user?.id;
|
||||
// const userId = session?.session?.factors?.user?.id;
|
||||
|
||||
if (userId) {
|
||||
return listAuthenticationMethodTypes(userId)
|
||||
.then((methods) => {
|
||||
return NextResponse.json(methods);
|
||||
})
|
||||
.catch((error) => {
|
||||
return NextResponse.json(error, { status: 500 });
|
||||
});
|
||||
} else {
|
||||
return NextResponse.json(
|
||||
{ details: "could not get session" },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
} else {
|
||||
return NextResponse.json({}, { status: 400 });
|
||||
}
|
||||
}
|
||||
// if (userId) {
|
||||
// return listAuthenticationMethodTypes(userId)
|
||||
// .then((methods) => {
|
||||
// return NextResponse.json(methods);
|
||||
// })
|
||||
// .catch((error) => {
|
||||
// return NextResponse.json(error, { status: 500 });
|
||||
// });
|
||||
// } else {
|
||||
// return NextResponse.json(
|
||||
// { details: "could not get session" },
|
||||
// { status: 500 }
|
||||
// );
|
||||
// }
|
||||
// } else {
|
||||
// return NextResponse.json({}, { status: 400 });
|
||||
// }
|
||||
// }
|
||||
|
||||
export async function POST(request: NextRequest) {
|
||||
const body = await request.json();
|
||||
if (body) {
|
||||
const { loginName } = body;
|
||||
const { loginName, authRequestId } = body;
|
||||
|
||||
const domain: string = request.nextUrl.hostname;
|
||||
|
||||
return createSessionAndUpdateCookie(loginName, undefined, domain, undefined)
|
||||
return createSessionAndUpdateCookie(
|
||||
loginName,
|
||||
undefined,
|
||||
domain,
|
||||
undefined,
|
||||
authRequestId
|
||||
)
|
||||
.then((session) => {
|
||||
if (session.factors?.user?.id) {
|
||||
return listAuthenticationMethodTypes(session.factors?.user?.id)
|
||||
|
||||
@@ -2,6 +2,7 @@ import {
|
||||
ZitadelServer,
|
||||
ZitadelServerOptions,
|
||||
user,
|
||||
oidc,
|
||||
settings,
|
||||
getServers,
|
||||
initializeServer,
|
||||
@@ -29,6 +30,10 @@ import {
|
||||
StartIdentityProviderFlowResponse,
|
||||
RetrieveIdentityProviderInformationRequest,
|
||||
RetrieveIdentityProviderInformationResponse,
|
||||
GetAuthRequestResponse,
|
||||
GetAuthRequestRequest,
|
||||
CreateCallbackRequest,
|
||||
CreateCallbackResponse,
|
||||
} from "@zitadel/server";
|
||||
|
||||
export const zitadelConfig: ZitadelServerOptions = {
|
||||
@@ -224,6 +229,28 @@ export async function retrieveIdentityProviderInformation(
|
||||
});
|
||||
}
|
||||
|
||||
export async function getAuthRequest(
|
||||
server: ZitadelServer,
|
||||
{ authRequestId }: GetAuthRequestRequest
|
||||
): Promise<GetAuthRequestResponse> {
|
||||
const oidcService = oidc.getOidc(server);
|
||||
|
||||
return oidcService.getAuthRequest({
|
||||
authRequestId,
|
||||
});
|
||||
}
|
||||
|
||||
export async function createCallback(
|
||||
server: ZitadelServer,
|
||||
{ authRequestId }: CreateCallbackRequest
|
||||
): Promise<CreateCallbackResponse> {
|
||||
const oidcService = oidc.getOidc(server);
|
||||
|
||||
return oidcService.createCallback({
|
||||
authRequestId,
|
||||
});
|
||||
}
|
||||
|
||||
export async function verifyEmail(
|
||||
server: ZitadelServer,
|
||||
userId: string,
|
||||
|
||||
@@ -15,12 +15,14 @@ type Inputs = {
|
||||
type Props = {
|
||||
loginSettings: LoginSettings | undefined;
|
||||
loginName: string | undefined;
|
||||
authRequestId: string | undefined;
|
||||
submit: boolean;
|
||||
};
|
||||
|
||||
export default function UsernameForm({
|
||||
loginSettings,
|
||||
loginName,
|
||||
authRequestId,
|
||||
submit,
|
||||
}: Props) {
|
||||
const { register, handleSubmit, formState } = useForm<Inputs>({
|
||||
@@ -37,14 +39,17 @@ export default function UsernameForm({
|
||||
|
||||
async function submitLoginName(values: Inputs) {
|
||||
setLoading(true);
|
||||
|
||||
const body = {
|
||||
loginName: values.loginName,
|
||||
};
|
||||
|
||||
const res = await fetch("/api/loginname", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
loginName: values.loginName,
|
||||
}),
|
||||
body: JSON.stringify(authRequestId ? { ...body, authRequestId } : body),
|
||||
});
|
||||
|
||||
setLoading(false);
|
||||
|
||||
@@ -7,6 +7,7 @@ export type SessionCookie = {
|
||||
token: string;
|
||||
loginName: string;
|
||||
changeDate: string;
|
||||
authRequestId?: string; // if its linked to an OIDC flow
|
||||
};
|
||||
|
||||
function setSessionHttpOnlyCookie(sessions: SessionCookie[]) {
|
||||
@@ -146,6 +147,18 @@ export async function getAllSessionIds(): Promise<any> {
|
||||
}
|
||||
}
|
||||
|
||||
export async function getAllSessions(): Promise<SessionCookie[]> {
|
||||
const cookiesList = cookies();
|
||||
const stringifiedCookie = cookiesList.get("sessions");
|
||||
|
||||
if (stringifiedCookie?.value) {
|
||||
const sessions: SessionCookie[] = JSON.parse(stringifiedCookie?.value);
|
||||
return sessions;
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns most recent session filtered by optinal loginName
|
||||
* @param loginName
|
||||
|
||||
@@ -10,7 +10,8 @@ export async function createSessionAndUpdateCookie(
|
||||
loginName: string,
|
||||
password: string | undefined,
|
||||
domain: string,
|
||||
challenges: ChallengeKind[] | undefined
|
||||
challenges: ChallengeKind[] | undefined,
|
||||
authRequestId: string | undefined
|
||||
): Promise<Session> {
|
||||
const createdSession = await createSession(
|
||||
server,
|
||||
@@ -34,6 +35,10 @@ export async function createSessionAndUpdateCookie(
|
||||
loginName: response.session?.factors?.user?.loginName ?? "",
|
||||
};
|
||||
|
||||
if (authRequestId) {
|
||||
sessionCookie.authRequestId = authRequestId;
|
||||
}
|
||||
|
||||
return addSessionToCookie(sessionCookie).then(() => {
|
||||
return response.session as Session;
|
||||
});
|
||||
@@ -57,7 +62,8 @@ export async function setSessionAndUpdateCookie(
|
||||
password: string | undefined,
|
||||
passkey: { credentialAssertionData: any } | undefined,
|
||||
domain: string | undefined,
|
||||
challenges: ChallengeKind[] | undefined
|
||||
challenges: ChallengeKind[] | undefined,
|
||||
authRequestId: string | undefined
|
||||
): Promise<SessionWithChallenges> {
|
||||
return setSession(
|
||||
server,
|
||||
@@ -76,6 +82,10 @@ export async function setSessionAndUpdateCookie(
|
||||
loginName: loginName,
|
||||
};
|
||||
|
||||
if (authRequestId) {
|
||||
sessionCookie.authRequestId = authRequestId;
|
||||
}
|
||||
|
||||
return getSession(server, sessionCookie.id, sessionCookie.token).then(
|
||||
(response) => {
|
||||
if (response?.session && response.session.factors?.user?.loginName) {
|
||||
@@ -87,6 +97,10 @@ export async function setSessionAndUpdateCookie(
|
||||
loginName: session.factors?.user?.loginName ?? "",
|
||||
};
|
||||
|
||||
if (sessionCookie.authRequestId) {
|
||||
newCookie.authRequestId = sessionCookie.authRequestId;
|
||||
}
|
||||
|
||||
return updateSessionCookie(sessionCookie.id, newCookie).then(() => {
|
||||
return { challenges: updatedSession.challenges, ...session };
|
||||
});
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import * as settings from "./v2/settings";
|
||||
import * as session from "./v2/session";
|
||||
import * as user from "./v2/user";
|
||||
import * as oidc from "./v2/oidc";
|
||||
import * as management from "./management";
|
||||
|
||||
import * as login from "./proto/server/zitadel/settings/v2alpha/login_settings";
|
||||
@@ -24,6 +25,13 @@ export {
|
||||
Challenges_Passkey,
|
||||
} from "./proto/server/zitadel/session/v2alpha/challenge";
|
||||
|
||||
export {
|
||||
GetAuthRequestRequest,
|
||||
GetAuthRequestResponse,
|
||||
CreateCallbackRequest,
|
||||
CreateCallbackResponse,
|
||||
} from "./proto/server/zitadel/oidc/v2alpha/oidc_service";
|
||||
|
||||
export {
|
||||
Session,
|
||||
Factors,
|
||||
@@ -96,4 +104,5 @@ export {
|
||||
login,
|
||||
password,
|
||||
legal,
|
||||
oidc,
|
||||
};
|
||||
|
||||
2
packages/zitadel-server/src/v2/oidc/index.ts
Normal file
2
packages/zitadel-server/src/v2/oidc/index.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
export * from "./oidc";
|
||||
export * from "../../proto/server/zitadel/oidc/v2alpha/oidc_service";
|
||||
24
packages/zitadel-server/src/v2/oidc/oidc.ts
Normal file
24
packages/zitadel-server/src/v2/oidc/oidc.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import { CompatServiceDefinition } from "nice-grpc/lib/service-definitions";
|
||||
|
||||
import { ZitadelServer, createClient, getServers } from "../../server";
|
||||
import { OIDCServiceClient, OIDCServiceDefinition } from ".";
|
||||
|
||||
export const getOidc = (server?: string | ZitadelServer) => {
|
||||
let config;
|
||||
if (server && typeof server === "string") {
|
||||
const apps = getServers();
|
||||
config = apps.find((a) => a.name === server)?.config;
|
||||
} else if (server && typeof server === "object") {
|
||||
config = server.config;
|
||||
}
|
||||
|
||||
if (!config) {
|
||||
throw Error("No ZITADEL server found");
|
||||
}
|
||||
|
||||
return createClient<OIDCServiceClient>(
|
||||
OIDCServiceDefinition as CompatServiceDefinition,
|
||||
config.apiUrl,
|
||||
config.token
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user