express-jwt
Advanced tools
Comparing version 1.2.0 to 1.3.0
var jwt = require('jsonwebtoken'); | ||
var UnauthorizedError = require('./errors/UnauthorizedError'); | ||
var unless = require('express-unless'); | ||
var async = require('async'); | ||
var DEFAULT_REVOKED_FUNCTION = function(_, __, cb) { return cb(null, false); } | ||
function wrapStaticSecretInCallback(secret){ | ||
@@ -20,2 +23,4 @@ return function(_, __, cb){ | ||
var isRevokedCallback = options.isRevoked || DEFAULT_REVOKED_FUNCTION; | ||
var _requestProperty = options.userProperty || options.requestProperty || 'user'; | ||
@@ -76,4 +81,18 @@ var credentialsRequired = typeof options.credentialsRequired === 'undefined' ? true : options.credentialsRequired; | ||
secretCallback(req, payload, function(err, secret){ | ||
async.parallel([ | ||
function(callback){ | ||
secretCallback(req, payload, callback); | ||
}, | ||
function(callback){ | ||
isRevokedCallback(req, payload, callback); | ||
} | ||
], function(err, results){ | ||
if (err) { return next(err); } | ||
var revoked = results[1]; | ||
if (revoked){ | ||
return next(new UnauthorizedError('revoked_token', { message: 'The token has been revoked.'})); | ||
} | ||
var secret = results[0]; | ||
jwt.verify(token, secret, options, function(err, decoded) { | ||
@@ -80,0 +99,0 @@ if (err && credentialsRequired) return next(new UnauthorizedError('invalid_token', err)); |
{ | ||
"name": "express-jwt", | ||
"version": "1.2.0", | ||
"version": "1.3.0", | ||
"description": "JWT authentication middleware.", | ||
@@ -38,3 +38,4 @@ "keywords": [ | ||
"express-unless": "0.0.0", | ||
"jsonwebtoken": "~3.2.2" | ||
"jsonwebtoken": "~3.2.2", | ||
"async": "^0.9.0" | ||
}, | ||
@@ -41,0 +42,0 @@ "devDependencies": { |
@@ -86,3 +86,3 @@ # express-jwt | ||
### Multi-tenancy | ||
If you are developing an application in which the secret used to sign tokens is not static, you can provide a callback function as the `secret` parameter. The function has the signature: `function(req, payload, cb)`: | ||
If you are developing an application in which the secret used to sign tokens is not static, you can provide a callback function as the `secret` parameter. The function has the signature: `function(req, payload, done)`: | ||
* `req` (`Object`) - The express `request` object. | ||
@@ -120,3 +120,35 @@ * `payload` (`Object`) - An object with the JWT claims. | ||
### Revoked tokens | ||
It is possible that some tokens will need to be revoked so they cannot be used any longer. You can provide a function as the `isRevoked` option. The signature of the function is `function(req, payload, done)`: | ||
* `req` (`Object`) - The express `request` object. | ||
* `payload` (`Object`) - An object with the JWT claims. | ||
* `done` (`Function`) - A function with signature `function(err, revoked)` to be invoked once the check to see if the token is revoked or not is complete. | ||
* `err` (`Any`) - The error that occurred. | ||
* `secret` (`Boolean`) - `true` if the JWT is revoked, `false` otherwise. | ||
For example, if the `(iss, jti)` claim pair is used to identify a JWT: | ||
```javascript | ||
var jwt = require('express-jwt'); | ||
var data = require('./data'); | ||
var utilities = requre('./utilities'); | ||
var isRevokedCallback = function(req, payload, done){ | ||
var issuer = payload.iss; | ||
var tokenId = payload.jti; | ||
data.getRevokedToken(issuer, tokenId, function(err, token){ | ||
if (err) { return done(err); } | ||
return done(null, !!token); | ||
}); | ||
}; | ||
app.get('/protected', | ||
jwt({secret: shhhhhhared-secret, | ||
isRevoked: isRevokedCallback}), | ||
function(req, res) { | ||
if (!req.user.admin) return res.send(401); | ||
res.send(200); | ||
}); | ||
``` | ||
### Error handling | ||
@@ -123,0 +155,0 @@ |
@@ -277,2 +277,80 @@ var jwt = require('jsonwebtoken'); | ||
}); | ||
it ('should fail if token is revoked', function(){ | ||
var token = jwt.sign({ iss: 'a', foo: 'bar'}, tenants.a.secret); | ||
req.headers = {}; | ||
req.headers.authorization = 'Bearer ' + token; | ||
var middleware = expressjwt({ | ||
secret: secretCallback, | ||
isRevoked: function(req, payload, done){ | ||
done(null, true); | ||
} | ||
})(req, res, function(err) { | ||
assert.ok(err); | ||
assert.equal(err.code, 'revoked_token'); | ||
assert.equal(err.message, 'The token has been revoked.'); | ||
}); | ||
}); | ||
}); | ||
describe('revoked jwts', function(){ | ||
var secret = 'shhhhhh'; | ||
var revoked_id = '1234' | ||
var middleware = expressjwt({ | ||
secret: secret, | ||
isRevoked: function(req, payload, done){ | ||
done(null, payload.jti && payload.jti === revoked_id); | ||
} | ||
}); | ||
it('should throw if token is revoked', function(){ | ||
var req = {}; | ||
var res = {}; | ||
var token = jwt.sign({ jti: revoked_id, foo: 'bar'}, secret); | ||
req.headers = {}; | ||
req.headers.authorization = 'Bearer ' + token; | ||
middleware(req, res, function(err) { | ||
assert.ok(err); | ||
assert.equal(err.code, 'revoked_token'); | ||
assert.equal(err.message, 'The token has been revoked.'); | ||
}); | ||
}); | ||
it('should work if token is not revoked', function(){ | ||
var req = {}; | ||
var res = {}; | ||
var token = jwt.sign({ jti: '1233', foo: 'bar'}, secret); | ||
req.headers = {}; | ||
req.headers.authorization = 'Bearer ' + token; | ||
middleware(req, res, function() { | ||
assert.equal('bar', req.user.foo); | ||
}); | ||
}); | ||
it('should throw if error occurs checking if token is revoked', function(){ | ||
var req = {}; | ||
var res = {}; | ||
var token = jwt.sign({ jti: revoked_id, foo: 'bar'}, secret); | ||
req.headers = {}; | ||
req.headers.authorization = 'Bearer ' + token; | ||
expressjwt({ | ||
secret: secret, | ||
isRevoked: function(req, payload, done){ | ||
done(new Error('An error ocurred')); | ||
} | ||
})(req, res, function(err) { | ||
assert.ok(err); | ||
assert.equal(err.message, 'An error ocurred'); | ||
}); | ||
}); | ||
}); |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
23721
390
206
3
1
+ Addedasync@^0.9.0
+ Addedasync@0.9.2(transitive)