From 722a98c249790865ed8f8e19b99b5b2d04f10b02 Mon Sep 17 00:00:00 2001 From: ort Date: Sat, 15 Aug 2026 16:35:56 -0400 Subject: [PATCH] Trust the reverse proxy so secure cookies actually get set With COOKIE_SECURE=true behind a TLS-terminating reverse proxy, Express only ever sees the proxy's plain-HTTP connection to the container, so req.secure was always false from its perspective. express-session silently refused to set a `secure` cookie on a connection it believed was insecure -- login would succeed (200, parent data returned) but no Set-Cookie ever reached the browser, so the very next request came back 401 and bounced to the login screen. Looked like "logs in, then immediately signs back out" -- reproduced on both Mac Chrome and iPhone once COOKIE_SECURE was turned on for push notifications. app.set('trust proxy', 1) when COOKIE_SECURE is true makes Express read X-Forwarded-Proto from the proxy, so it correctly sees the connection as secure. Tied to COOKIE_SECURE rather than a new flag since it's the same "yes, I'm behind an HTTPS-terminating proxy" fact either way. Verified: no Set-Cookie without the header (correct -- a request that didn't actually come through the proxy shouldn't get one), Set-Cookie with Secure/SameSite correctly present given X-Forwarded-Proto: https, and a full login-then-auth-check cycle staying authenticated. --- src/app.js | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/app.js b/src/app.js index 83f6399..f2509e2 100644 --- a/src/app.js +++ b/src/app.js @@ -19,6 +19,20 @@ const { getChildByToken } = require('./middleware/resolveKiosk'); const app = express(); app.disable('x-powered-by'); + +// Needed whenever this sits behind a TLS-terminating reverse proxy (i.e. +// whenever COOKIE_SECURE=true): Express only sees the proxy's plain-HTTP +// connection to the container, so without this, req.secure is always +// false from Express's point of view — and express-session silently +// refuses to set a `secure` cookie on a request it thinks is insecure, +// even though the browser really did connect over HTTPS. That looks like +// "login succeeds, but you're immediately signed back out" to a user. +// Tied to COOKIE_SECURE rather than a separate flag: the same "yes, I'm +// behind an HTTPS-terminating proxy" fact drives both. +if (config.cookieSecure) { + app.set('trust proxy', 1); +} + app.use(express.json({ limit: '256kb' })); app.use(session({