check for valid sessions, cleanup

This commit is contained in:
Max Peintner
2024-12-09 09:44:56 +01:00
parent 1a7d97421f
commit 2e2ae590f9

View File

@@ -9,7 +9,7 @@ import {
listSessions, listSessions,
startIdentityProviderFlow, startIdentityProviderFlow,
} from "@/lib/zitadel"; } from "@/lib/zitadel";
import { create } from "@zitadel/client"; import { create, timestampDate } from "@zitadel/client";
import { import {
AuthRequest, AuthRequest,
Prompt, Prompt,
@@ -37,26 +37,53 @@ const ORG_SCOPE_REGEX = /urn:zitadel:iam:org:id:([0-9]+)/;
const ORG_DOMAIN_SCOPE_REGEX = /urn:zitadel:iam:org:domain:primary:(.+)/; // TODO: check regex for all domain character options const ORG_DOMAIN_SCOPE_REGEX = /urn:zitadel:iam:org:domain:primary:(.+)/; // TODO: check regex for all domain character options
const IDP_SCOPE_REGEX = /urn:zitadel:iam:org:idp:id:(.+)/; const IDP_SCOPE_REGEX = /urn:zitadel:iam:org:idp:id:(.+)/;
function findSession( function isSessionValid(session: Session): boolean {
const validPassword = session?.factors?.password?.verifiedAt;
const validPasskey = session?.factors?.webAuthN?.verifiedAt;
const validIDP = session?.factors?.intent?.verifiedAt;
const stillValid = session.expirationDate
? timestampDate(session.expirationDate) > new Date()
: true;
const validFactors = !!(
(validPassword || validPasskey || validIDP) &&
stillValid
);
return stillValid && validFactors;
}
function findValidSession(
sessions: Session[], sessions: Session[],
authRequest: AuthRequest, authRequest: AuthRequest,
): Session | undefined { ): Session | undefined {
const validSessionsWithHint = sessions
.filter((s) => {
if (authRequest.hintUserId) { if (authRequest.hintUserId) {
console.log(`find session for hintUserId: ${authRequest.hintUserId}`); return s.factors?.user?.id === authRequest.hintUserId;
return sessions.find((s) => s.factors?.user?.id === authRequest.hintUserId);
} }
if (authRequest.loginHint) { if (authRequest.loginHint) {
console.log(`find session for loginHint: ${authRequest.loginHint}`); return s.factors?.user?.loginName === authRequest.loginHint;
return sessions.find(
(s) => s.factors?.user?.loginName === authRequest.loginHint,
);
}
if (sessions.length) {
return sessions[0];
} }
return false;
})
.filter(isSessionValid);
if (validSessionsWithHint.length === 0) {
return undefined; return undefined;
} }
validSessionsWithHint.sort((a, b) => {
const dateA = a.changeDate ? timestampDate(a.changeDate).getTime() : 0;
const dateB = b.changeDate ? timestampDate(b.changeDate).getTime() : 0;
return dateB - dateA;
});
// return most recently changed session
return sessions[0];
}
export async function GET(request: NextRequest) { export async function GET(request: NextRequest) {
const searchParams = request.nextUrl.searchParams; const searchParams = request.nextUrl.searchParams;
const authRequestId = searchParams.get("authRequest"); const authRequestId = searchParams.get("authRequest");
@@ -226,8 +253,8 @@ export async function GET(request: NextRequest) {
if (authRequest && authRequest.prompt.includes(Prompt.CREATE)) { if (authRequest && authRequest.prompt.includes(Prompt.CREATE)) {
const registerUrl = new URL("/register", request.url); const registerUrl = new URL("/register", request.url);
if (authRequest?.id) { if (authRequest.id) {
registerUrl.searchParams.set("authRequestId", authRequest?.id); registerUrl.searchParams.set("authRequestId", authRequest.id);
} }
if (organization) { if (organization) {
registerUrl.searchParams.set("organization", organization); registerUrl.searchParams.set("organization", organization);
@@ -260,8 +287,8 @@ export async function GET(request: NextRequest) {
} }
const loginNameUrl = new URL("/loginname", request.url); const loginNameUrl = new URL("/loginname", request.url);
if (authRequest?.id) { if (authRequest.id) {
loginNameUrl.searchParams.set("authRequestId", authRequest?.id); loginNameUrl.searchParams.set("authRequestId", authRequest.id);
} }
if (authRequest.loginHint) { if (authRequest.loginHint) {
loginNameUrl.searchParams.set("loginName", authRequest.loginHint); loginNameUrl.searchParams.set("loginName", authRequest.loginHint);
@@ -272,19 +299,31 @@ export async function GET(request: NextRequest) {
return NextResponse.redirect(loginNameUrl); return NextResponse.redirect(loginNameUrl);
} else if (authRequest.prompt.includes(Prompt.NONE)) { } else if (authRequest.prompt.includes(Prompt.NONE)) {
// NONE prompt - silent authentication // NONE prompt - silent authentication
const selectedSession = findValidSession(sessions, authRequest);
let selectedSession = findSession(sessions, authRequest); if (!selectedSession || !selectedSession.id) {
return NextResponse.json(
{ error: "No active session found" },
{ status: 400 },
);
}
if (selectedSession && selectedSession.id) {
const cookie = sessionCookies.find( const cookie = sessionCookies.find(
(cookie) => cookie.id === selectedSession?.id, (cookie) => cookie.id === selectedSession.id,
); );
if (cookie && cookie.id && cookie.token) { if (!cookie || !cookie.id || !cookie.token) {
return NextResponse.json(
{ error: "No active session found" },
{ status: 400 },
);
}
const session = { const session = {
sessionId: cookie?.id, sessionId: cookie.id,
sessionToken: cookie?.token, sessionToken: cookie.token,
}; };
const { callbackUrl } = await createCallback( const { callbackUrl } = await createCallback(
create(CreateCallbackRequestSchema, { create(CreateCallbackRequestSchema, {
authRequestId, authRequestId,
@@ -296,31 +335,26 @@ export async function GET(request: NextRequest) {
); );
return NextResponse.redirect(callbackUrl); return NextResponse.redirect(callbackUrl);
} else { } else {
return NextResponse.json( // check for loginHint, userId hint and valid sessions
{ error: "No active session found" }, let selectedSession = findValidSession(sessions, authRequest);
{ status: 400 }, // TODO: check for correct status code
); if (!selectedSession || !selectedSession.id) {
} return gotoAccounts();
} else { }
return NextResponse.json(
{ error: "No active session found" },
{ status: 400 }, // TODO: check for correct status code
);
}
} else {
// check for loginHint, userId hint sessions
let selectedSession = findSession(sessions, authRequest);
if (selectedSession && selectedSession.id) {
const cookie = sessionCookies.find( const cookie = sessionCookies.find(
(cookie) => cookie.id === selectedSession?.id, (cookie) => cookie.id === selectedSession.id,
); );
if (cookie && cookie.id && cookie.token) { if (!cookie || !cookie.id || !cookie.token) {
return gotoAccounts();
}
const session = { const session = {
sessionId: cookie?.id, sessionId: cookie.id,
sessionToken: cookie?.token, sessionToken: cookie.token,
}; };
try { try {
const { callbackUrl } = await createCallback( const { callbackUrl } = await createCallback(
create(CreateCallbackRequestSchema, { create(CreateCallbackRequestSchema, {
@@ -343,12 +377,6 @@ export async function GET(request: NextRequest) {
console.error(error); console.error(error);
return gotoAccounts(); return gotoAccounts();
} }
} else {
return gotoAccounts();
}
} else {
return gotoAccounts();
}
} }
} else { } else {
const loginNameUrl = new URL("/loginname", request.url); const loginNameUrl = new URL("/loginname", request.url);