override cookie sameSite settings

This commit is contained in:
Max Peintner
2025-04-30 09:41:00 +02:00
parent a690b254c4
commit 77e9f6f2e9
3 changed files with 99 additions and 51 deletions

View File

@@ -20,7 +20,10 @@ export type Cookie = {
type SessionCookie<T> = Cookie & T;
async function setSessionHttpOnlyCookie<T>(sessions: SessionCookie<T>[]) {
async function setSessionHttpOnlyCookie<T>(
sessions: SessionCookie<T>[],
sameSite: boolean | "lax" | "strict" | "none" = true,
) {
const cookiesList = await cookies();
return cookiesList.set({
@@ -28,6 +31,7 @@ async function setSessionHttpOnlyCookie<T>(sessions: SessionCookie<T>[]) {
value: JSON.stringify(sessions),
httpOnly: true,
path: "/",
sameSite,
});
}
@@ -42,10 +46,15 @@ export async function setLanguageCookie(language: string) {
});
}
export async function addSessionToCookie<T>(
session: SessionCookie<T>,
cleanup: boolean = false,
): Promise<any> {
export async function addSessionToCookie<T>({
session,
cleanup,
sameSite,
}: {
session: SessionCookie<T>;
cleanup?: boolean;
sameSite?: boolean | "lax" | "strict" | "none" | undefined;
}): Promise<any> {
const cookiesList = await cookies();
const stringifiedCookie = cookiesList.get("sessions");
@@ -79,17 +88,23 @@ export async function addSessionToCookie<T>(
? timestampDate(timestampFromMs(Number(session.expirationTs))) > now
: true,
);
return setSessionHttpOnlyCookie(filteredSessions);
return setSessionHttpOnlyCookie(filteredSessions, sameSite);
} else {
return setSessionHttpOnlyCookie(currentSessions);
return setSessionHttpOnlyCookie(currentSessions, sameSite);
}
}
export async function updateSessionCookie<T>(
id: string,
session: SessionCookie<T>,
cleanup: boolean = false,
): Promise<any> {
export async function updateSessionCookie<T>({
id,
session,
cleanup,
sameSite,
}: {
id: string;
session: SessionCookie<T>;
cleanup?: boolean;
sameSite?: boolean | "lax" | "strict" | "none" | undefined;
}): Promise<any> {
const cookiesList = await cookies();
const stringifiedCookie = cookiesList.get("sessions");
@@ -108,19 +123,24 @@ export async function updateSessionCookie<T>(
? timestampDate(timestampFromMs(Number(session.expirationTs))) > now
: true,
);
return setSessionHttpOnlyCookie(filteredSessions);
return setSessionHttpOnlyCookie(filteredSessions, sameSite);
} else {
return setSessionHttpOnlyCookie(sessions);
return setSessionHttpOnlyCookie(sessions, sameSite);
}
} else {
throw "updateSessionCookie<T>: session id now found";
}
}
export async function removeSessionFromCookie<T>(
session: SessionCookie<T>,
cleanup: boolean = false,
): Promise<any> {
export async function removeSessionFromCookie<T>({
session,
cleanup,
sameSite,
}: {
session: SessionCookie<T>;
cleanup?: boolean;
sameSite?: boolean | "lax" | "strict" | "none" | undefined;
}): Promise<any> {
const cookiesList = await cookies();
const stringifiedCookie = cookiesList.get("sessions");
@@ -136,9 +156,9 @@ export async function removeSessionFromCookie<T>(
? timestampDate(timestampFromMs(Number(session.expirationTs))) > now
: true,
);
return setSessionHttpOnlyCookie(filteredSessions);
return setSessionHttpOnlyCookie(filteredSessions, sameSite);
} else {
return setSessionHttpOnlyCookie(reducedSessions);
return setSessionHttpOnlyCookie(reducedSessions, sameSite);
}
}

View File

@@ -4,6 +4,7 @@ import { addSessionToCookie, updateSessionCookie } from "@/lib/cookies";
import {
createSessionForUserIdAndIdpIntent,
createSessionFromChecks,
getSecuritySettings,
getSession,
setSession,
} from "@/lib/zitadel";
@@ -65,7 +66,7 @@ export async function createSessionAndUpdateCookie(command: {
serviceUrl,
sessionId: createdSession.sessionId,
sessionToken: createdSession.sessionToken,
}).then((response) => {
}).then(async (response) => {
if (response?.session && response.session?.factors?.user?.loginName) {
const sessionCookie: CustomCookieData = {
id: createdSession.sessionId,
@@ -91,9 +92,14 @@ export async function createSessionAndUpdateCookie(command: {
response.session.factors.user.organizationId;
}
return addSessionToCookie(sessionCookie).then(() => {
return response.session as Session;
});
const securitySettings = await getSecuritySettings({ serviceUrl });
const sameSite = securitySettings?.embeddedIframe?.enabled
? "none"
: true;
await addSessionToCookie({ session: sessionCookie, sameSite });
return response.session as Session;
} else {
throw "could not get session or session does not have loginName";
}
@@ -167,7 +173,10 @@ export async function createSessionForIdpAndUpdateCookie(
sessionCookie.organization = session.factors.user.organizationId;
}
return addSessionToCookie(sessionCookie).then(() => {
const securitySettings = await getSecuritySettings({ serviceUrl });
const sameSite = securitySettings?.embeddedIframe?.enabled ? "none" : true;
return addSessionToCookie({ session: sessionCookie, sameSite }).then(() => {
return session as Session;
});
}
@@ -217,32 +226,44 @@ export async function setSessionAndUpdateCookie(
serviceUrl,
sessionId: sessionCookie.id,
sessionToken: sessionCookie.token,
}).then((response) => {
if (response?.session && response.session.factors?.user?.loginName) {
const { session } = response;
const newCookie: CustomCookieData = {
id: sessionCookie.id,
token: updatedSession.sessionToken,
creationTs: sessionCookie.creationTs,
expirationTs: sessionCookie.expirationTs,
// just overwrite the changeDate with the new one
changeTs: updatedSession.details?.changeDate
? `${timestampMs(updatedSession.details.changeDate)}`
: "",
loginName: session.factors?.user?.loginName ?? "",
organization: session.factors?.user?.organizationId ?? "",
};
if (sessionCookie.requestId) {
newCookie.requestId = sessionCookie.requestId;
}
return updateSessionCookie(sessionCookie.id, newCookie).then(() => {
return { challenges: updatedSession.challenges, ...session };
});
} else {
}).then(async (response) => {
if (
!response?.session ||
!response.session.factors?.user?.loginName
) {
throw "could not get session or session does not have loginName";
}
const { session } = response;
const newCookie: CustomCookieData = {
id: sessionCookie.id,
token: updatedSession.sessionToken,
creationTs: sessionCookie.creationTs,
expirationTs: sessionCookie.expirationTs,
// just overwrite the changeDate with the new one
changeTs: updatedSession.details?.changeDate
? `${timestampMs(updatedSession.details.changeDate)}`
: "",
loginName: session.factors?.user?.loginName ?? "",
organization: session.factors?.user?.organizationId ?? "",
};
if (sessionCookie.requestId) {
newCookie.requestId = sessionCookie.requestId;
}
const securitySettings = await getSecuritySettings({ serviceUrl });
const sameSite = securitySettings?.embeddedIframe?.enabled
? "none"
: true;
return updateSessionCookie({
id: sessionCookie.id,
session: newCookie,
sameSite,
}).then(() => {
return { challenges: updatedSession.challenges, ...session };
});
});
} else {
throw "Session not be set";

View File

@@ -4,6 +4,7 @@ import { setSessionAndUpdateCookie } from "@/lib/server/cookie";
import {
deleteSession,
getLoginSettings,
getSecuritySettings,
humanMFAInitSkipped,
listAuthenticationMethodTypes,
} from "@/lib/zitadel";
@@ -209,8 +210,11 @@ export async function clearSession(options: ClearSessionOptions) {
sessionToken: session.token,
});
const securitySettings = await getSecuritySettings({ serviceUrl });
const sameSite = securitySettings?.embeddedIframe?.enabled ? "none" : true;
if (deletedSession) {
return removeSessionFromCookie(session);
return removeSessionFromCookie({ session, sameSite });
}
}
@@ -230,9 +234,12 @@ export async function cleanupSession({ sessionId }: CleanupSessionCommand) {
sessionToken: sessionCookie.token,
});
const securitySettings = await getSecuritySettings({ serviceUrl });
const sameSite = securitySettings?.embeddedIframe?.enabled ? "none" : true;
if (!deleteResponse) {
throw new Error("Could not delete session");
}
return removeSessionFromCookie(sessionCookie);
return removeSessionFromCookie({ session: sessionCookie, sameSite });
}