diff --git a/worklenz-backend/package-lock.json b/worklenz-backend/package-lock.json index ad69ba32..4fffff20 100644 --- a/worklenz-backend/package-lock.json +++ b/worklenz-backend/package-lock.json @@ -73,6 +73,7 @@ "@types/compression": "^1.7.2", "@types/connect-flash": "^0.0.37", "@types/cookie-parser": "^1.4.3", + "@types/cookie-signature": "^1.1.2", "@types/cron": "^2.0.1", "@types/crypto-js": "^4.2.2", "@types/csurf": "^1.11.2", @@ -5445,6 +5446,16 @@ "@types/express": "*" } }, + "node_modules/@types/cookie-signature": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@types/cookie-signature/-/cookie-signature-1.1.2.tgz", + "integrity": "sha512-2OhrZV2LVnUAXklUFwuYUTokalh/dUb8rqt70OW6ByMSxYpauPZ+kfNLknX3aJyjY5iu8i3cUyoLZP9Fn37tTg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/cors": { "version": "2.8.19", "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.19.tgz", diff --git a/worklenz-backend/package.json b/worklenz-backend/package.json index d1922c58..1b8d140f 100644 --- a/worklenz-backend/package.json +++ b/worklenz-backend/package.json @@ -108,6 +108,7 @@ "@types/compression": "^1.7.2", "@types/connect-flash": "^0.0.37", "@types/cookie-parser": "^1.4.3", + "@types/cookie-signature": "^1.1.2", "@types/cron": "^2.0.1", "@types/crypto-js": "^4.2.2", "@types/csurf": "^1.11.2", diff --git a/worklenz-backend/src/middlewares/session-middleware.ts b/worklenz-backend/src/middlewares/session-middleware.ts index 41c54a06..6f4196e2 100644 --- a/worklenz-backend/src/middlewares/session-middleware.ts +++ b/worklenz-backend/src/middlewares/session-middleware.ts @@ -1,6 +1,7 @@ import session from "express-session"; import db from "../config/db"; import { isProduction } from "../shared/utils"; +import * as cookieSignature from "cookie-signature"; // eslint-disable-next-line @typescript-eslint/no-var-requires const pgSession = require("connect-pg-simple")(session); @@ -52,25 +53,39 @@ export default (req: any, res: any, next: any) => { if (headerSessionId && headerSessionName) { console.log("Mobile app using header-based session:", headerSessionId); - // The session store expects a signed cookie, but we need to construct it properly - // For now, let's try the exact format from the successful login session - const sessionCookie = `${headerSessionName}=s%3A${headerSessionId}`; + // The problem is cookie signature - we need to create a properly signed cookie + const secret = process.env.SESSION_SECRET || "development-secret-key"; - if (req.headers.cookie) { - // Replace existing session cookie while keeping other cookies - req.headers.cookie = req.headers.cookie - .split(';') - .filter((cookie: string) => !cookie.trim().startsWith(headerSessionName)) - .concat(sessionCookie) - .join(';'); - } else { - // Set the session cookie from header + try { + // Create a signed cookie using the session secret + const signedSessionId = 's:' + cookieSignature.sign(headerSessionId, secret); + const encodedSignedId = encodeURIComponent(signedSessionId); + const sessionCookie = `${headerSessionName}=${encodedSignedId}`; + + console.log("Creating signed session cookie:"); + console.log("- Raw session ID:", headerSessionId); + console.log("- Signed session ID:", signedSessionId); + console.log("- Encoded signed ID:", encodedSignedId); + console.log("- Final cookie:", sessionCookie); + + if (req.headers.cookie) { + // Replace existing session cookie while keeping other cookies + req.headers.cookie = req.headers.cookie + .split(';') + .filter((cookie: string) => !cookie.trim().startsWith(headerSessionName)) + .concat(sessionCookie) + .join(';'); + } else { + // Set the session cookie from header + req.headers.cookie = sessionCookie; + } + console.log("Updated cookie header:", req.headers.cookie); + } catch (error) { + console.log("Error creating signed cookie:", error); + // Fallback to the old method + const sessionCookie = `${headerSessionName}=s%3A${headerSessionId}`; req.headers.cookie = sessionCookie; } - console.log("Updated cookie header:", req.headers.cookie); - - // Also debug what the session middleware will see - console.log("Expected session lookup for ID:", headerSessionId); } sessionMiddleware(req, res, (err: any) => {