From 0ec2ec3f2a7f8b8a3b8f7b5722d8abd9e76b5925 Mon Sep 17 00:00:00 2001 From: Oliver Bryan <04oliverbryan@gmail.com> Date: Fri, 9 Jan 2026 05:32:37 +0000 Subject: [PATCH] updated JWT to include sessionId and added cookie helpers --- packages/backend/src/auth/utils.ts | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/packages/backend/src/auth/utils.ts b/packages/backend/src/auth/utils.ts index e2f4686..b466fc7 100644 --- a/packages/backend/src/auth/utils.ts +++ b/packages/backend/src/auth/utils.ts @@ -2,7 +2,8 @@ import bcrypt from "bcrypt"; import * as jwt from "jsonwebtoken"; const JWT_EXPIRES_IN = (process.env.JWT_EXPIRES_IN ?? "7d") as jwt.SignOptions["expiresIn"]; -const JWT_ALGORITHM = "HS256"; +const JWT_ALGORITHM = "HS256" as const; +const COOKIE_MAX_AGE = 7 * 24 * 60 * 60; // 7 days in seconds const requireJwtSecret = () => { const secret = process.env.JWT_SECRET; @@ -19,9 +20,9 @@ export const hashPassword = (password: string) => bcrypt.hash(password, 10); export const verifyPassword = (password: string, hash: string) => bcrypt.compare(password, hash); -export const generateToken = (userId: number) => { +export const generateToken = (sessionId: number, userId: number) => { const secret = requireJwtSecret(); - return jwt.sign({ userId }, secret, { + return jwt.sign({ sessionId, userId }, secret, { expiresIn: JWT_EXPIRES_IN, algorithm: JWT_ALGORITHM, }); @@ -31,5 +32,23 @@ export const verifyToken = (token: string) => { const secret = requireJwtSecret(); return jwt.verify(token, secret, { algorithms: [JWT_ALGORITHM], - }) as { userId: number }; + }) as { sessionId: number; userId: number }; +}; + +export const buildAuthCookie = (token: string) => { + return `token=${token}; HttpOnly; Secure; SameSite=None; Path=/; Max-Age=${COOKIE_MAX_AGE}`; // it pains me that this is in seconds +}; + +export const buildClearAuthCookie = () => { + return "token=; HttpOnly; Secure; SameSite=None; Path=/; Max-Age=0"; +}; + +export const parseCookies = (cookieHeader: string | null): Record => { + if (!cookieHeader) return {}; + return Object.fromEntries( + cookieHeader.split(";").map((cookie) => { + const [key, ...rest] = cookie.trim().split("="); + return [key, rest.join("=")]; + }), + ); };