-
Notifications
You must be signed in to change notification settings - Fork 126
/
index.js
112 lines (102 loc) · 4.66 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
var Boom = require('boom'); // error handling https://github.com/hapijs/boom
var assert = require('assert');
var JWT = require('jsonwebtoken'); // https://github.com/docdis/learn-json-web-tokens
var extract = require('./extract'); // extract token from Auth Header, URL or Coookie
var pkg = require('../package.json');
var internals = {}; // Declare internals >> see: http://hapijs.com/styleguide
exports.register = function (server, options, next) {
server.auth.scheme('jwt', internals.implementation);
next();
};
exports.register.attributes = { // hapi requires attributes for a plugin.
pkg: pkg // See: http://hapijs.com/tutorials/plugins
};
internals.isFunction = function (functionToCheck) {
var getType = {};
return functionToCheck && getType.toString.call(functionToCheck) === '[object Function]';
};
internals.implementation = function (server, options) {
assert(options, 'options are required for jwt auth scheme'); // pre-auth checks
assert(options.validateFunc || options.verifyFunc, 'validateFunc OR verifyFunc function is required!')
return {
authenticate: function (request, reply) {
var token = extract(request, options); // extract token from Header, Cookie or Query param
if (!token) {
return reply(Boom.unauthorized(null, 'Token'));
}
if (!extract.isValid(token)) { // quick check for validity of token format
return reply(Boom.unauthorized('Invalid token format', 'Token'));
} // verification is done later, but we want to avoid decoding if malformed
request.auth.token = token; // keep encoded JWT available in the request lifecycle
// otherwise use the same key (String) to validate all JWTs
var decoded;
try {
decoded = JWT.decode(token, { complete: options.complete || false });
}
catch(e) { // request should still FAIL if the token does not decode.
return reply(Boom.unauthorized('Invalid token format', 'Token'));
}
if(options.key && typeof options.validateFunc === 'function') {
// if the keyFunc is a function it allows dynamic key lookup see: https://github.com/dwyl/hapi-auth-jwt2/issues/16
var keyFunc = (internals.isFunction(options.key)) ? options.key : function (decoded, callback) { callback(null, options.key); };
keyFunc(decoded, function (err, key, extraInfo) {
if (err) {
return reply(Boom.wrap(err));
}
if (extraInfo) {
request.plugins[pkg.name] = { extraInfo: extraInfo };
}
var verifyOptions = options.verifyOptions || {};
JWT.verify(token, key, verifyOptions, function (err, decoded) {
if (err) {
return reply(Boom.unauthorized('Invalid token', 'Token'), null, { credentials: null });
}
else { // see: http://hapijs.com/tutorials/auth for validateFunc signature
options.validateFunc(decoded, request, function (err, valid, credentials) { // bring your own checks
if (err) {
return reply(Boom.wrap(err));
}
else if (!valid) {
return reply(Boom.unauthorized('Invalid credentials', 'Token'), null, { credentials: credentials || decoded });
}
else {
return reply.continue({ credentials: credentials || decoded, artifacts: token });
}
});
}
});
}); // END keyFunc
} // END check for (secret) key and validateFunc
else { // see: https://github.com/dwyl/hapi-auth-jwt2/issues/130
options.verifyFunc(decoded, request, function(err, valid, credentials) {
if (err) {
return reply(Boom.wrap(err));
}
else if (!valid) {
return reply(Boom.unauthorized('Invalid credentials', 'Token'), null, { credentials: decoded });
} else {
return reply.continue({ credentials: credentials, artifacts: token });
}
});
}
// else { // warn the person that the plugin requires either a validateFunc or verifyFunc!
// return reply(Boom.notImplemented('please specify a hapi-auth-jwt2 validateFunc or verifyFunc.', 'Token'), null, { credentials: decoded });
// }
},
response: function(request, reply) {
if(options.responseFunc && typeof options.responseFunc === 'function') {
options.responseFunc(request, reply, function(err) {
if (err) {
return reply(Boom.wrap(err));
}
else {
reply.continue();
}
})
}
else {
reply.continue();
}
}
};
};