Skip to content

Commit 2673736

Browse files
lincondbjohansebasUlisesGascon
authored
feat: add support to dynamic cookie options (#1027)
Co-authored-by: Sebastian Beltran <bjohansebas@gmail.com> Co-authored-by: Ulises Gascón <ulisesgascongonzalez@gmail.com>
1 parent 73e0193 commit 2673736

File tree

4 files changed

+97
-3
lines changed

4 files changed

+97
-3
lines changed

HISTORY.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,27 @@
22

33
### 🚀 Improvements
44

5+
* Add dynamic cookie options support
6+
7+
Cookie options can now be dynamic, allowing for more flexible and context-aware configuration based on each request. This feature enables programmatic modification of cookie attributes like `secure`, `httpOnly`, `sameSite`, `maxAge`, `domain`, and `path` based on session or request conditions.
8+
9+
```js
10+
var app = express()
11+
app.use(session({
12+
secret: 'keyboard cat',
13+
resave: false,
14+
saveUninitialized: true,
15+
cookie: function (req) {
16+
var match = req.url.match(/^\/([^/]+)/);
17+
return {
18+
path: match ? '/' + match[1] : '/',
19+
httpOnly: true,
20+
secure: req.secure || false,
21+
maxAge: 60000
22+
}
23+
}
24+
}))
25+
```
526
* Add sameSite 'auto' support for automatic SameSite attribute configuration
627

728
Added `sameSite: 'auto'` option for cookie configuration that automatically sets `SameSite=None` for HTTPS and `SameSite=Lax` for HTTP connections, simplifying cookie handling across different environments.

README.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,26 @@ For a list of stores, see [compatible session stores](#compatible-session-stores
4949
Settings object for the session ID cookie. The default value is
5050
`{ path: '/', httpOnly: true, secure: false, maxAge: null }`.
5151

52+
In addition to providing a static object, you can also pass a callback function to dynamically generate the cookie options for each request. The callback receives the `req` object as its argument and should return an object containing the cookie settings.
53+
54+
```js
55+
var app = express()
56+
app.use(session({
57+
secret: 'keyboard cat',
58+
resave: false,
59+
saveUninitialized: true,
60+
cookie: function(req) {
61+
var match = req.url.match(/^\/([^/]+)/);
62+
return {
63+
path: match ? '/' + match[1] : '/',
64+
httpOnly: true,
65+
secure: req.secure || false,
66+
maxAge: 60000
67+
}
68+
}
69+
}))
70+
```
71+
5272
The following are options that can be set in this object.
5373

5474
##### cookie.domain

index.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ var defer = typeof setImmediate === 'function'
7070
* Setup session store with the given `options`.
7171
*
7272
* @param {Object} [options]
73-
* @param {Object} [options.cookie] Options for cookie
73+
* @param {Object|Function} [options.cookie] Options for cookie
7474
* @param {Function} [options.genid]
7575
* @param {String} [options.name=connect.sid] Session ID cookie name
7676
* @param {Boolean} [options.proxy]
@@ -158,7 +158,7 @@ function session(options) {
158158
store.generate = function(req){
159159
req.sessionID = generateId(req);
160160
req.session = new Session(req);
161-
req.session.cookie = new Cookie(cookieOptions);
161+
req.session.cookie = new Cookie(typeof cookieOptions === 'function' ? cookieOptions(req) : cookieOptions);
162162

163163
var isSecure = issecure(req, trustProxy);
164164

@@ -199,7 +199,8 @@ function session(options) {
199199

200200
// pathname mismatch
201201
var originalPath = parseUrl.original(req).pathname || '/'
202-
if (originalPath.indexOf(cookieOptions.path || '/') !== 0) {
202+
var resolvedCookieOptions = typeof cookieOptions === 'function' ? cookieOptions(req) : cookieOptions
203+
if (originalPath.indexOf(resolvedCookieOptions.path || '/') !== 0) {
203204
debug('pathname mismatch')
204205
next()
205206
return

test/session.js

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -802,6 +802,58 @@ describe('session()', function(){
802802
})
803803
})
804804

805+
describe('when "cookie" is a function', function () {
806+
it('should call custom function and apply cookie options', function (done) {
807+
var cookieCallbackCalled = false;
808+
var cookieCallback = function () {
809+
cookieCallbackCalled = true;
810+
return { path: '/test', httpOnly: true, secure: false };
811+
};
812+
var server = createServer({ cookie: cookieCallback });
813+
request(server)
814+
.get('/test')
815+
.expect(
816+
shouldSetCookieWithAttributeAndValue('connect.sid', 'Path', '/test')
817+
)
818+
.expect(shouldSetCookieWithAttribute('connect.sid', 'HttpOnly'))
819+
.expect(shouldSetCookieWithoutAttribute('connect.sid', 'Secure'))
820+
.expect(200, function (err) {
821+
if (err) return done(err);
822+
assert.strictEqual(
823+
cookieCallbackCalled,
824+
true,
825+
'should have called cookie callback'
826+
);
827+
done();
828+
});
829+
});
830+
831+
it('should provide req argument', function (done) {
832+
var _path = '/test';
833+
var cookieCallbackCalled = false;
834+
var cookieCallback = function (req) {
835+
cookieCallbackCalled = true;
836+
return { path: req.url, httpOnly: true, secure: false };
837+
};
838+
var server = createServer({ cookie: cookieCallback });
839+
request(server)
840+
.get(_path)
841+
.expect(
842+
shouldSetCookieWithAttributeAndValue('connect.sid', 'Path', _path)
843+
)
844+
.expect(shouldSetCookieWithAttribute('connect.sid', 'HttpOnly'))
845+
.expect(shouldSetCookieWithoutAttribute('connect.sid', 'Secure'))
846+
.expect(200, function (err) {
847+
if (err) return done(err);
848+
assert.strictEqual(
849+
cookieCallbackCalled,
850+
true,
851+
'should have called cookie callback'
852+
);
853+
done();
854+
});
855+
});
856+
});
805857
describe('when "sameSite" set to "auto"', function () {
806858
describe('basic functionality', function () {
807859
before(function () {

0 commit comments

Comments
 (0)