index.js 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. var jwt = require('jsonwebtoken');
  2. var UnauthorizedError = require('./errors/UnauthorizedError');
  3. var unless = require('express-unless');
  4. var async = require('async');
  5. var set = require('lodash.set');
  6. var DEFAULT_REVOKED_FUNCTION = function(_, __, cb) { return cb(null, false); };
  7. function isFunction(object) {
  8. return Object.prototype.toString.call(object) === '[object Function]';
  9. }
  10. function wrapStaticSecretInCallback(secret){
  11. return function(_, __, cb){
  12. return cb(null, secret);
  13. };
  14. }
  15. module.exports = function(options) {
  16. if (!options || !options.secret) throw new Error('secret should be set');
  17. if (!options.algorithms) throw new Error('algorithms should be set');
  18. if (!Array.isArray(options.algorithms)) throw new Error('algorithms must be an array');
  19. var secretCallback = options.secret;
  20. if (!isFunction(secretCallback)){
  21. secretCallback = wrapStaticSecretInCallback(secretCallback);
  22. }
  23. var isRevokedCallback = options.isRevoked || DEFAULT_REVOKED_FUNCTION;
  24. var _requestProperty = options.userProperty || options.requestProperty || 'user';
  25. var _resultProperty = options.resultProperty;
  26. var credentialsRequired = typeof options.credentialsRequired === 'undefined' ? true : options.credentialsRequired;
  27. var middleware = function(req, res, next) {
  28. var token;
  29. if (req.method === 'OPTIONS' && req.headers.hasOwnProperty('access-control-request-headers')) {
  30. var hasAuthInAccessControl = !!~req.headers['access-control-request-headers']
  31. .split(',').map(function (header) {
  32. return header.trim();
  33. }).indexOf('authorization');
  34. if (hasAuthInAccessControl) {
  35. return next();
  36. }
  37. }
  38. if (options.getToken && typeof options.getToken === 'function') {
  39. try {
  40. token = options.getToken(req);
  41. } catch (e) {
  42. return next(e);
  43. }
  44. } else if (req.headers && req.headers.authorization) {
  45. var parts = req.headers.authorization.split(' ');
  46. if (parts.length == 2) {
  47. var scheme = parts[0];
  48. var credentials = parts[1];
  49. if (/^Bearer$/i.test(scheme)) {
  50. token = credentials;
  51. } else {
  52. if (credentialsRequired) {
  53. return next(new UnauthorizedError('credentials_bad_scheme', { message: 'Format is Authorization: Bearer [token]' }));
  54. } else {
  55. return next();
  56. }
  57. }
  58. } else {
  59. return next(new UnauthorizedError('credentials_bad_format', { message: 'Format is Authorization: Bearer [token]' }));
  60. }
  61. }
  62. if (!token) {
  63. if (credentialsRequired) {
  64. return next(new UnauthorizedError('credentials_required', { message: 'No authorization token was found' }));
  65. } else {
  66. return next();
  67. }
  68. }
  69. var dtoken;
  70. try {
  71. dtoken = jwt.decode(token, { complete: true }) || {};
  72. } catch (err) {
  73. return next(new UnauthorizedError('invalid_token', err));
  74. }
  75. async.waterfall([
  76. function getSecret(callback){
  77. var arity = secretCallback.length;
  78. if (arity == 4) {
  79. secretCallback(req, dtoken.header, dtoken.payload, callback);
  80. } else { // arity == 3
  81. secretCallback(req, dtoken.payload, callback);
  82. }
  83. },
  84. function verifyToken(secret, callback) {
  85. jwt.verify(token, secret, options, function(err, decoded) {
  86. if (err) {
  87. callback(new UnauthorizedError('invalid_token', err));
  88. } else {
  89. callback(null, decoded);
  90. }
  91. });
  92. },
  93. function checkRevoked(decoded, callback) {
  94. isRevokedCallback(req, dtoken.payload, function (err, revoked) {
  95. if (err) {
  96. callback(err);
  97. }
  98. else if (revoked) {
  99. callback(new UnauthorizedError('revoked_token', {message: 'The token has been revoked.'}));
  100. } else {
  101. callback(null, decoded);
  102. }
  103. });
  104. }
  105. ], function (err, result){
  106. if (err) { return next(err); }
  107. if (_resultProperty) {
  108. set(res, _resultProperty, result);
  109. } else {
  110. set(req, _requestProperty, result);
  111. }
  112. next();
  113. });
  114. };
  115. middleware.unless = unless;
  116. middleware.UnauthorizedError = UnauthorizedError;
  117. return middleware;
  118. };
  119. module.exports.UnauthorizedError = UnauthorizedError;