Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ By default, this is `false`.
- `'lax'` will set the `SameSite` attribute to `Lax` for lax same site enforcement.
- `'none'` will set the `SameSite` attribute to `None` for an explicit cross-site cookie.
- `'strict'` will set the `SameSite` attribute to `Strict` for strict same site enforcement.
- `'auto'` will set the `SameSite` attribute to `None` for secure connections and `Lax` for non-secure connections.

More information about the different enforcement levels can be found in
[the specification][rfc-6265bis-03-4.1.2.7].
Expand All @@ -141,6 +142,14 @@ the future. This also means many clients may ignore this attribute until they un
that requires that the `Secure` attribute be set to `true` when the `SameSite` attribute has been
set to `'none'`. Some web browsers or other clients may be adopting this specification.

The `cookie.sameSite` option can also be set to the special value `'auto'` to have
this setting automatically match the determined security of the connection. When the connection
is secure (HTTPS), the `SameSite` attribute will be set to `None` to enable cross-site usage.
When the connection is not secure (HTTP), the `SameSite` attribute will be set to `Lax` for
better security while maintaining functionality. This is useful when the Express `"trust proxy"`
setting is properly setup to simplify development vs production configuration, particularly
for SAML authentication scenarios.

##### cookie.secure

Specifies the `boolean` value for the `Secure` `Set-Cookie` attribute. When truthy,
Expand Down
4 changes: 4 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,10 @@ function session(options) {
if (cookieOptions.secure === 'auto') {
req.session.cookie.secure = issecure(req, trustProxy);
}

if (cookieOptions.sameSite === 'auto') {
req.session.cookie.sameSite = issecure(req, trustProxy) ? 'none' : 'lax';
}
};

var storeImplementsTouch = typeof store.touch === 'function';
Expand Down
102 changes: 102 additions & 0 deletions test/session.js
Original file line number Diff line number Diff line change
Expand Up @@ -801,6 +801,108 @@ describe('session()', function(){
})
})
})

describe('when "sameSite" set to "auto"', function () {
describe('basic functionality', function () {
before(function () {
function setup (req) {
req.secure = JSON.parse(req.headers['x-secure'])
}

function respond (req, res) {
res.end(String(req.secure))
}

this.server = createServer(setup, { cookie: { sameSite: 'auto' } }, respond)
})

it('should set SameSite=None for secure connections', function (done) {
request(this.server)
.get('/')
.set('X-Secure', 'true')
.expect(shouldSetCookieWithAttributeAndValue('connect.sid', 'SameSite', 'None'))
.expect(200, 'true', done)
})

it('should set SameSite=Lax for insecure connections', function (done) {
request(this.server)
.get('/')
.set('X-Secure', 'false')
.expect(shouldSetCookieWithAttributeAndValue('connect.sid', 'SameSite', 'Lax'))
.expect(200, 'false', done)
})
})

describe('with proxy settings', function () {
describe('when "proxy" is "true"', function () {
before(function () {
this.server = createServer({ proxy: true, cookie: { sameSite: 'auto' }})
})

it('should set SameSite=None when X-Forwarded-Proto is https', function (done) {
request(this.server)
.get('/')
.set('X-Forwarded-Proto', 'https')
.expect(shouldSetCookieWithAttributeAndValue('connect.sid', 'SameSite', 'None'))
.expect(200, done)
})

it('should set SameSite=Lax when X-Forwarded-Proto is http', function (done) {
request(this.server)
.get('/')
.set('X-Forwarded-Proto', 'http')
.expect(shouldSetCookieWithAttributeAndValue('connect.sid', 'SameSite', 'Lax'))
.expect(200, done)
})
})

describe('when "proxy" is "false"', function () {
before(function () {
this.server = createServer({ proxy: false, cookie: { sameSite: 'auto' }})
})

it('should set SameSite=Lax when X-Forwarded-Proto is https', function (done) {
request(this.server)
.get('/')
.set('X-Forwarded-Proto', 'https')
.expect(shouldSetCookieWithAttributeAndValue('connect.sid', 'SameSite', 'Lax'))
.expect(200, done)
})
})
})

describe('combined with secure auto', function() {
before(function () {
function setup (req) {
req.secure = JSON.parse(req.headers['x-secure'])
}

function respond (req, res) {
res.end(String(req.secure))
}

this.server = createServer(setup, { cookie: { secure: 'auto', sameSite: 'auto' } }, respond)
})

it('should set both Secure and SameSite=None when secure', function (done) {
request(this.server)
.get('/')
.set('X-Secure', 'true')
.expect(shouldSetCookieWithAttribute('connect.sid', 'Secure'))
.expect(shouldSetCookieWithAttributeAndValue('connect.sid', 'SameSite', 'None'))
.expect(200, 'true', done)
})

it('should set neither Secure nor SameSite=None when insecure', function (done) {
request(this.server)
.get('/')
.set('X-Secure', 'false')
.expect(shouldSetCookieWithoutAttribute('connect.sid', 'Secure'))
.expect(shouldSetCookieWithAttributeAndValue('connect.sid', 'SameSite', 'Lax'))
.expect(200, 'false', done)
})
})
})
})

describe('genid option', function(){
Expand Down