From 3f3f2bc22f8e1aacda30f40d715596d4b8c81fe0 Mon Sep 17 00:00:00 2001 From: Spencer Hawkins Date: Mon, 15 Oct 2018 19:42:58 -0700 Subject: [PATCH] Set payload to request even if token fails to verify (closes #158) --- README.md | 9 ++++++++- lib/index.js | 2 ++ test/jwt.test.js | 16 ++++++++++++++++ 3 files changed, 26 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index e8c3972e..c2630d19 100644 --- a/README.md +++ b/README.md @@ -64,8 +64,9 @@ var publicKey = fs.readFileSync('/path/to/public.pub'); jwt({ secret: publicKey }); ``` -By default, the decoded token is attached to `req.user` but can be configured with the `requestProperty` option. +When the token can be decoded _and_ verified, by default, the decoded token is attached to `req.user` but can be configured with the `requestProperty` option. +When the token can be decoded _but not necessarily verified_, by default, the decoded token is attached to `req.decoded` regardless of if an error is thrown. The specific property set can be configured with the `decodedProperty` option. (This can be useful for error handling; see "Error handling" for more info.) ```javascript jwt({ secret: publicKey, requestProperty: 'auth' }); @@ -174,6 +175,12 @@ The default behavior is to throw an error when the token is invalid, so you can ```javascript app.use(function (err, req, res, next) { if (err.name === 'UnauthorizedError') { + console.log(`error with token: ${err.message}`) + if (req.decoded) { + console.log(`The following token was decoded, but could not verified: ${req.decoded}`) + } else { + console.log(`The token could not be decoded`) + } res.status(401).send('invalid token...'); } }); diff --git a/lib/index.js b/lib/index.js index f5da77fc..34a6be8f 100644 --- a/lib/index.js +++ b/lib/index.js @@ -28,6 +28,7 @@ module.exports = function(options) { var isRevokedCallback = options.isRevoked || DEFAULT_REVOKED_FUNCTION; var _requestProperty = options.userProperty || options.requestProperty || 'user'; + var _requestDecodedProperty = options.decodedProperty || options.requestDecodedProperty || 'decoded'; var _resultProperty = options.resultProperty; var credentialsRequired = typeof options.credentialsRequired === 'undefined' ? true : options.credentialsRequired; @@ -83,6 +84,7 @@ module.exports = function(options) { try { dtoken = jwt.decode(token, { complete: true }) || {}; + set(req, _requestDecodedProperty, dtoken.payload); } catch (err) { return next(new UnauthorizedError('invalid_token', err)); } diff --git a/test/jwt.test.js b/test/jwt.test.js index 8062b8e6..8c855dc2 100644 --- a/test/jwt.test.js +++ b/test/jwt.test.js @@ -99,6 +99,22 @@ describe('failure tests', function () { }); }); + it('should include decoded and not user token if jwt decodes but doesn\'t verify', function() { + var secret = 'shhhhhh'; + var token = jwt.sign({foo: 'bar'}, secret); + + req.headers = {}; + req.headers.authorization = 'Bearer ' + token; + expressjwt({secret: 'different-shhhh'})(req, res, function(err) { + assert.ok(err); + assert.ok(req.decoded) + assert.equal(req.user, undefined) + assert.equal(err.code, 'invalid_token'); + assert.equal(req.decoded.foo, 'bar'); + assert.equal(err.message, 'invalid signature'); + }); + }); + it('should throw if audience is not expected', function() { var secret = 'shhhhhh'; var token = jwt.sign({foo: 'bar', aud: 'expected-audience'}, secret);