Created
December 8, 2020 13:42
-
-
Save aeros281/5679157e34efae42151a8fa10042bd0d to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var jwt = require('jsonwebtoken'); | |
var UnauthorizedError = require('./errors/UnauthorizedError'); | |
var unless = require('express-unless'); | |
var async = require('async'); | |
var set = require('lodash.set'); | |
var DEFAULT_REVOKED_FUNCTION = function(_, __, cb) { return cb(null, false); }; | |
module.exports = function(options) { | |
if (!options || !options.secret) throw new Error('secret should be set'); | |
if (!options.algorithms) throw new Error('algorithms should be set'); | |
if (!Array.isArray(options.algorithms)) throw new Error('algorithms must be an array'); | |
var secret = options.secret; | |
var isRevokedCallback = options.isRevoked || DEFAULT_REVOKED_FUNCTION; | |
var _requestProperty = options.userProperty || options.requestProperty || 'user'; | |
var _resultProperty = options.resultProperty; | |
var credentialsRequired = typeof options.credentialsRequired === 'undefined' ? true : options.credentialsRequired; | |
var result = function(req, res, next) { | |
var token; | |
if (req.method === 'OPTIONS' && req.headers.hasOwnProperty('access-control-request-headers')) { | |
var isValid = !!~req.headers['access-control-request-headers'] | |
.split(',').map(function (header) { | |
return header.trim(); | |
}).indexOf('authorization'); | |
if (isValid) { | |
return next(); | |
} | |
} | |
if (options.getToken && typeof options.getToken === 'function') { | |
try { | |
token = options.getToken(req); | |
} catch (e) { | |
return next(e); | |
} | |
} else if (req.headers && req.headers.authorization) { | |
var parts = req.headers.authorization.split(' '); | |
if (parts.length == 2) { | |
var scheme = parts[0]; | |
var credentials = parts[1]; | |
if (/^Bearer$/i.test(scheme)) { | |
token = credentials; | |
} else { | |
if (credentialsRequired) { | |
return next(new UnauthorizedError('credentials_bad_scheme', { message: 'Format is Authorization: Bearer [token]' })); | |
} else { | |
return next(); | |
} | |
} | |
} else { | |
return next(new UnauthorizedError('credentials_bad_format', { message: 'Format is Authorization: Bearer [token]' })); | |
} | |
} | |
if (!token) { | |
if (credentialsRequired) { | |
return next(new UnauthorizedError('credentials_required', { message: 'No authorization token was found' })); | |
} else { | |
return next(); | |
} | |
} | |
var dtoken; | |
try { | |
dtoken = jwt.decode(token, { complete: true }) || {}; | |
} catch (err) { | |
return next(new UnauthorizedError('invalid_token', err)); | |
} | |
async.waterfall([ | |
function getSecret(callback){ | |
callback(null, secret); | |
}, | |
function verifyToken(secret, callback) { | |
jwt.verify(token, secret, options, function(err, decoded) { | |
if (err) { | |
callback(new UnauthorizedError('invalid_token', err)); | |
} else { | |
callback(null, decoded); | |
} | |
}); | |
}, | |
function checkRevoked(decoded, callback) { | |
isRevokedCallback(req, dtoken.payload, function (err, revoked) { | |
if (err) { | |
callback(err); | |
} | |
else if (revoked) { | |
callback(new UnauthorizedError('revoked_token', {message: 'The token has been revoked.'})); | |
} else { | |
callback(null, decoded); | |
} | |
}); | |
} | |
], function (err, result){ | |
if (err) { return next(err); } | |
if (_resultProperty) { | |
set(res, _resultProperty, result); | |
} else { | |
set(req, _requestProperty, result); | |
} | |
next(); | |
}); | |
}; | |
result.unless = unless; | |
result.UnauthorizedError = UnauthorizedError; | |
return result; | |
}; | |
module.exports.UnauthorizedError = UnauthorizedError; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment