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.
This commit is contained in:
ort
2026-08-15 16:35:56 -04:00
parent fdba8c0d1f
commit 722a98c249
+14
View File
@@ -19,6 +19,20 @@ const { getChildByToken } = require('./middleware/resolveKiosk');
const app = express(); const app = express();
app.disable('x-powered-by'); 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(express.json({ limit: '256kb' }));
app.use(session({ app.use(session({