Skip to content

feat: accept function for options.credentials #337

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
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
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,9 @@ app.listen(80, function () {
* `methods`: Configures the **Access-Control-Allow-Methods** CORS header. Expects a comma-delimited string (ex: 'GET,PUT,POST') or an array (ex: `['GET', 'PUT', 'POST']`).
* `allowedHeaders`: Configures the **Access-Control-Allow-Headers** CORS header. Expects a comma-delimited string (ex: 'Content-Type,Authorization') or an array (ex: `['Content-Type', 'Authorization']`). If not specified, defaults to reflecting the headers specified in the request's **Access-Control-Request-Headers** header.
* `exposedHeaders`: Configures the **Access-Control-Expose-Headers** CORS header. Expects a comma-delimited string (ex: 'Content-Range,X-Content-Range') or an array (ex: `['Content-Range', 'X-Content-Range']`). If not specified, no custom headers are exposed.
* `credentials`: Configures the **Access-Control-Allow-Credentials** CORS header. Set to `true` to pass the header, otherwise it is omitted.
* `credentials`: Configures the **Access-Control-Allow-Credentials** CORS header. Possible values:
- `Boolean` - set `credentials` to `true` to pass the header, otherwise it is omitted.
- `Function` - set `credentials` to a function implementing some custom logic. The function takes the request as the only parameter. Return `true` from this function to pass the header, otherwise it is omitted.
* `maxAge`: Configures the **Access-Control-Max-Age** CORS header. Set to an integer to pass the header, otherwise it is omitted.
* `preflightContinue`: Pass the CORS preflight response to the next handler.
* `optionsSuccessStatus`: Provides a status code to use for successful `OPTIONS` requests, since some legacy browsers (IE11, various SmartTVs) choke on `204`.
Expand Down
9 changes: 5 additions & 4 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,9 @@
};
}

function configureCredentials(options) {
if (options.credentials === true) {
function configureCredentials(options, req) {
if (options.credentials === true ||
(typeof options.credentials === 'function' && options.credentials(req) === true)) {
return {
key: 'Access-Control-Allow-Credentials',
value: 'true'
Expand Down Expand Up @@ -163,7 +164,7 @@
if (method === 'OPTIONS') {
// preflight
headers.push(configureOrigin(options, req));
headers.push(configureCredentials(options))
headers.push(configureCredentials(options, req))
headers.push(configureMethods(options))
headers.push(configureAllowedHeaders(options, req));
headers.push(configureMaxAge(options))
Expand All @@ -182,7 +183,7 @@
} else {
// actual response
headers.push(configureOrigin(options, req));
headers.push(configureCredentials(options))
headers.push(configureCredentials(options, req))
headers.push(configureExposedHeaders(options))
applyHeaders(headers, res);
next();
Expand Down
39 changes: 39 additions & 0 deletions test/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -586,6 +586,45 @@ var util = require('util')
cors()(req, res, next);
});

describe('credentials configured with function', function () {
function conditionalCredentials(req) {
console.log('conditionalCredentials()', 'origin:', req.headers.origin);
var match = req.headers.origin === 'http://example.com';
console.log('conditionalCredentials()', 'match:', match);
return match;
}

it('includes credentials if provided function returns true', function (done) {
var cb = after(1, done)
var req = fakeRequest('OPTIONS')
var res = fakeResponse()

res.on('finish', function () {
assert.equal(res.getHeader('Access-Control-Allow-Credentials'), 'true')
cb()
})

cors({ credentials: conditionalCredentials })(req, res, function (err) {
cb(err || new Error('should not be called'))
})
});

it('does not include credentials if provided function returns false', function (done) {
var cb = after(1, done)
var req = fakeRequest('OPTIONS', { origin: 'http://unmatched.example.com' });
var res = fakeResponse();

res.on('finish', function () {
assert.equal(res.getHeader('Access-Control-Allow-Credentials'), undefined)
cb()
})

cors({ credentials: conditionalCredentials })(req, res, function (err) {
cb(err || new Error('should not be called'))
})
});
});

it('includes maxAge when specified', function (done) {
var cb = after(1, done)
var req = new FakeRequest('OPTIONS')
Expand Down