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