From f98bf9c7cb9505c80366711aeaae57308d2b74b7 Mon Sep 17 00:00:00 2001 From: Christopher Pruijsen Date: Sat, 10 Oct 2026 07:55:13 +0100 Subject: [PATCH] fix: refresh cookie attributes for rolling sessions When rolling is enabled, the session identifier cookie is re-sent on every response, but its attributes were inflated from the stored session data, so changes to the cookie option (such as sameSite, secure, or path) never applied to existing sessions. Build the re-sent cookie from the current resolved cookie options when a session is inflated with rolling enabled, while keeping the session's own expires and originalMaxAge. --- index.js | 29 +++++++++++++++++++---- test/session.js | 62 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 86 insertions(+), 5 deletions(-) diff --git a/index.js b/index.js index 3e23e901..e9f74786 100644 --- a/index.js +++ b/index.js @@ -158,19 +158,26 @@ function session(options) { store.generate = function(req){ req.sessionID = generateId(req); req.session = new Session(req); - var resolvedCookieOptions = typeof cookieOptions === 'function' ? cookieOptions(req) : cookieOptions; - req.session.cookie = new Cookie(resolvedCookieOptions); + req.session.cookie = createCookie(req); + }; + // create a new cookie for the request from + // the resolved cookie options + function createCookie(req) { + var resolvedCookieOptions = typeof cookieOptions === 'function' ? cookieOptions(req) : cookieOptions; + var sessionCookie = new Cookie(resolvedCookieOptions); var isSecure = issecure(req, trustProxy); if (resolvedCookieOptions.secure === 'auto') { - req.session.cookie.secure = isSecure; + sessionCookie.secure = isSecure; } if (resolvedCookieOptions.sameSite === 'auto') { - req.session.cookie.sameSite = isSecure ? 'none' : 'lax'; + sessionCookie.sameSite = isSecure ? 'none' : 'lax'; } - }; + + return sessionCookie; + } var storeImplementsTouch = typeof store.touch === 'function'; @@ -389,6 +396,18 @@ function session(options) { // inflate the session function inflate (req, sess) { store.createSession(req, sess) + + if (rollingSessions) { + // refresh the cookie attributes from the current + // options, keeping the session's own expiration + var expires = req.session.cookie.expires + var originalMaxAge = req.session.cookie.originalMaxAge + + req.session.cookie = createCookie(req) + req.session.cookie.expires = expires + req.session.cookie.originalMaxAge = originalMaxAge + } + originalId = req.sessionID originalHash = hash(sess) diff --git a/test/session.js b/test/session.js index 405e3ddf..ab20f67b 100644 --- a/test/session.js +++ b/test/session.js @@ -1229,6 +1229,68 @@ describe('session()', function(){ .expect(shouldSetCookie('connect.sid')) .expect(200, done); }); + + it('should send updated cookie attributes on existing session', function (done) { + var store = new session.MemoryStore() + var server = createServer({ + cookie: { maxAge: 60000, sameSite: 'none' }, + rolling: true, + store: store + }, function (req, res) { + req.session.user = 'bob' + res.end() + }) + + request(server) + .get('/') + .expect(shouldSetCookieWithAttributeAndValue('connect.sid', 'SameSite', 'None')) + .expect(200, function (err, res) { + if (err) return done(err) + + var updatedServer = createServer({ + cookie: { maxAge: 120000, sameSite: 'strict' }, + rolling: true, + store: store + }) + + request(updatedServer) + .get('/') + .set('Cookie', cookie(res)) + .expect(shouldSetCookieWithAttributeAndValue('connect.sid', 'SameSite', 'Strict')) + .expect(shouldSetCookieToExpireIn('connect.sid', 60000)) + .expect(200, done) + }) + }) + + it('should honor session cookie changes on existing session', function (done) { + var store = new session.MemoryStore() + var server = createServer({ rolling: true, store: store }, function (req, res) { + req.session.user = 'bob' + res.end() + }) + + request(server) + .get('/') + .expect(shouldSetCookie('connect.sid')) + .expect(200, function (err, res) { + if (err) return done(err) + + var updatedServer = createServer({ + cookie: { maxAge: 120000, sameSite: 'strict' }, + rolling: true, + store: store + }, function (req, res) { + req.session.cookie.sameSite = 'lax' + res.end() + }) + + request(updatedServer) + .get('/') + .set('Cookie', cookie(res)) + .expect(shouldSetCookieWithAttributeAndValue('connect.sid', 'SameSite', 'Lax')) + .expect(200, done) + }) + }) }); describe('resave option', function(){