Files
documenso/packages/auth/server/lib/session/session-cookies.ts
2025-02-19 16:07:04 +11:00

112 lines
2.9 KiB
TypeScript

import type { Context } from 'hono';
import { deleteCookie, getSignedCookie, setSignedCookie } from 'hono/cookie';
import {
formatSecureCookieName,
getCookieDomain,
useSecureCookies,
} from '@documenso/lib/constants/auth';
import { appLog } from '@documenso/lib/utils/debugger';
import { env } from '@documenso/lib/utils/env';
import { generateSessionToken } from './session';
export const sessionCookieName = formatSecureCookieName('sessionId');
export const csrfCookieName = formatSecureCookieName('csrfToken');
const getAuthSecret = () => {
const authSecret = env('NEXTAUTH_SECRET');
if (!authSecret) {
throw new Error('NEXTAUTH_SECRET is not set');
}
return authSecret;
};
/**
* Generic auth session cookie options.
*/
export const sessionCookieOptions = {
httpOnly: true,
path: '/',
sameSite: useSecureCookies ? 'none' : 'lax', // Todo: (RR7) This feels wrong?
secure: useSecureCookies,
domain: getCookieDomain(),
// Todo: (RR7) Max age for specific auth cookies.
} as const;
export const extractSessionCookieFromHeaders = (headers: Headers): string | null => {
const cookieHeader = headers.get('cookie') || '';
const cookiePairs = cookieHeader.split(';');
const sessionCookie = cookiePairs.find((pair) => pair.trim().startsWith(sessionCookieName));
if (!sessionCookie) {
return null;
}
return sessionCookie.split('=')[1].trim();
};
/**
* Get the session cookie attached to the request headers.
*
* @param c - The Hono context.
* @returns The session ID or null if no session cookie is found.
*/
export const getSessionCookie = async (c: Context): Promise<string | null> => {
const sessionId = await getSignedCookie(c, getAuthSecret(), sessionCookieName);
return sessionId || null;
};
/**
* Set the session cookie into the Hono context.
*
* @param c - The Hono context.
* @param sessionToken - The session token to set.
*/
export const setSessionCookie = async (c: Context, sessionToken: string) => {
await setSignedCookie(
c,
sessionCookieName,
sessionToken,
getAuthSecret(),
sessionCookieOptions,
).catch((err) => {
appLog('SetSessionCookie', `Error setting signed cookie: ${err}`);
throw err;
});
};
/**
* Set the session cookie into the Hono context.
*
* @param c - The Hono context.
* @param sessionToken - The session token to set.
*/
export const deleteSessionCookie = (c: Context) => {
deleteCookie(c, sessionCookieName, sessionCookieOptions);
};
export const getCsrfCookie = async (c: Context) => {
const csrfToken = await getSignedCookie(c, getAuthSecret(), csrfCookieName);
return csrfToken || null;
};
export const setCsrfCookie = async (c: Context) => {
const csrfToken = generateSessionToken();
await setSignedCookie(c, csrfCookieName, csrfToken, getAuthSecret(), {
...sessionCookieOptions,
// Explicity set to undefined for session lived cookie.
expires: undefined,
maxAge: undefined,
});
return csrfToken;
};