Launch Week Day 5: Introducing Reachability for PHP.Learn More
Socket
Book a DemoSign in
Socket

hapi-auth-jwt2

Package Overview
Dependencies
Maintainers
1
Versions
94
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

hapi-auth-jwt2 - npm Package Compare versions

Comparing version
7.1.0
to
7.1.1
+339
test/basic.test.js
var test = require('tape');
var JWT = require('jsonwebtoken');
var secret = 'NeverShareYourSecret';
var server = require('./basic_server'); // test server which in turn loads our module
test("Attempt to access restricted content (without auth token)", function(t) {
var options = {
method: "POST",
url: "/privado"
};
// server.inject lets us simulate an http request
server.inject(options, function(response) {
t.equal(response.statusCode, 401, "No Token should fail");
t.end();
});
});
test("Attempt to access restricted content (with an INVALID Token)", function(t) {
var options = {
method: "POST",
url: "/privado",
headers: { authorization: "Bearer fails.validation" }
};
// server.inject lets us simulate an http request
server.inject(options, function(response) {
t.equal(response.statusCode, 401, "INVALID Token should fail");
t.end();
});
});
test("Malformed JWT", function(t) {
// use the token as the 'authorization' header in requests
// var token = jwt.sign({ "id": 1 ,"name":"Old Greg" }, 'incorrectSecret');
// console.log(token);
var options = {
method: "POST",
url: "/privado",
headers: { authorization: "Bearer my.invalid.token" }
};
// server.inject lets us simulate an http request
server.inject(options, function(response) {
// console.log(response.result);
// console.log(' '); // blank line
t.equal(response.statusCode, 401, "INVALID Token should fail");
// t.equal(JSON.parse(response.result).msg, 'Invalid Token', "INVALID Token should fail");
t.end();
});
});
test("Try using a token with missing characters in body", function(t) {
// use the token as the 'authorization' header in requests
var token = JWT.sign({ id: 123, "name": "Charlie" }, secret);
// delete some characters in body
var tokenData = token.split('.');
var header = tokenData[0],
body = tokenData[1],
signature = tokenData[2];
token = header + '.' + body.substring(0, body.length - 1) + '.' + signature;
/*console.log(" - - - - - - token - - - - -");
console.log(token);*/
var options = {
method: "POST",
url: "/privado",
headers: { authorization: "Bearer " + token }
};
// server.inject lets us simulate an http request
server.inject(options, function(response) {
t.equal(response.statusCode, 401, "INVALID Token should fail");
t.end();
});
});
test("Try using an incorrect secret to sign the JWT", function(t) {
// use the token as the 'authorization' header in requests
var token = JWT.sign({ id: 123, "name": "Charlie" }, 'incorrectSecret');
// console.log(" - - - - - - token - - - - -")
// console.log(token);
var options = {
method: "POST",
url: "/privado",
headers: { authorization: "Bearer " + token }
};
// server.inject lets us simulate an http request
server.inject(options, function(response) {
t.equal(response.statusCode, 401, "Token signed with incorrect key fails");
t.end();
});
});
// see: https://github.com/dwyl/hapi-auth-jwt2/issues/166
// test.only("Try using an expired token", function(t) {
// // use the token as the 'authorization' header in requests
// var token = JWT.sign({ id: 123, "name": "Charlie" }, secret, { expiresInSeconds: 1 });
// console.log(" - - - - - - token - - - - -")
// console.log(token);
// var options = {
// method: "POST",
// url: "/privado",
// headers: { authorization: "Bearer " + token }
// };
// // server.inject lets us simulate an http request
// setTimeout(function () {
// server.inject(options, function(response) {
// t.equal(response.statusCode, 401, "Expired token should be invalid");
// t.equal(response.result.message, 'Token expired', 'Message should be "Token expired"');
// t.end();
// });
// }, 1000);
// });
test("Token is well formed but is allowed=false so should be denied", function(t) {
// use the token as the 'authorization' header in requests
// var token = jwt.sign({ "id": 1 ,"name":"Old Greg" }, 'incorrectSecret');
var token = JWT.sign({ id: 321, "name": "Old Gregg" }, secret);
var options = {
method: "POST",
url: "/privado",
headers: { authorization: "Bearer " + token }
};
// server.inject lets us simulate an http request
server.inject(options, function(response) {
t.equal(response.statusCode, 401, "Denied");
t.end();
});
});
test("Access restricted content (with VALID Token)", function(t) {
// use the token as the 'authorization' header in requests
var token = JWT.sign({ id: 123, "name": "Charlie" }, secret);
var options = {
method: "POST",
url: "/privado",
headers: { authorization: "Bearer " + token }
};
// server.inject lets us simulate an http request
server.inject(options, function(response) {
// console.log(" - - - - RESPONSE: ")
// console.log(response.result);
t.equal(response.statusCode, 200, "VALID Token should succeed!");
t.end();
});
});
test("Access restricted content (with Well-formed but invalid Token)", function(t) {
// use the token as the 'authorization' header in requests
var token = JWT.sign({ id: 123, "name": "Charlie" }, 'badsecret');
var options = {
method: "POST",
url: "/privado",
headers: { authorization: "Bearer " + token }
};
// server.inject lets us simulate an http request
server.inject(options, function(response) {
// console.log(" - - - - RESPONSE: ")
// console.log(response.result);
t.equal(response.statusCode, 401, "InVALID Token should Error!");
t.end();
});
});
// see: https://github.com/ideaq/hapi-auth-jwt2/issues/28
test("Request with undefined auth header should 401", function(t) {
var options = {
method: "POST",
url: "/privado",
headers: { authorization: "Bearer " }
};
// server.inject lets us simulate an http request
server.inject(options, function(response) {
// console.log(" - - - - RESPONSE: ")
// console.log(response.result);
t.equal(response.statusCode, 401, "InVALID Token fails (as expected)!");
t.end();
});
});
test("Auth mode 'required' should require authentication header", function(t) {
var options = {
method: "POST",
url: "/required"
};
// server.inject lets us simulate an http request
server.inject(options, function(response) {
t.equal(response.statusCode, 401, "No token header should fail in auth 'required' mode");
t.end();
});
});
test("Auth mode 'required' should fail with invalid token", function(t) {
// use the token as the 'authorization' header in requests
var token = JWT.sign({ id: 123, "name": "Charlie" }, 'badsecret');
var options = {
method: "POST",
url: "/required",
headers: { authorization: "Bearer " + token }
};
// server.inject lets us simulate an http request
server.inject(options, function(response) {
// console.log(" - - - - RESPONSE: ")
// console.log(response.result);
t.equal(response.statusCode, 401, "Invalid token should error!");
t.end();
});
});
test("Auth mode 'required' should should pass with valid token", function(t) {
// use the token as the 'authorization' header in requests
var token = JWT.sign({ id: 123, "name": "Charlie" }, secret);
var options = {
method: "POST",
url: "/required",
headers: { authorization: "Bearer " + token }
};
// server.inject lets us simulate an http request
server.inject(options, function(response) {
// console.log(" - - - - RESPONSE: ")
// console.log(response.result);
t.equal(response.statusCode, 200, "Valid token should succeed!");
t.end();
});
});
test("Auth mode 'optional' should pass when no auth header specified", function(t) {
var options = {
method: "POST",
url: "/optional"
};
server.inject(options, function(response) {
// console.log(" - - - - RESPONSE: ")
// console.log(response.result);
t.equal(response.statusCode, 200, "No auth header should pass in optional mode!");
t.end();
});
});
test("Auth mode 'optional' should fail with invalid token", function(t) {
// use the token as the 'authorization' header in requests
var token = JWT.sign({ id: 123, "name": "Charlie" }, 'badsecret');
var options = {
method: "POST",
url: "/optional",
headers: { authorization: "Bearer " + token }
};
// server.inject lets us simulate an http request
server.inject(options, function(response) {
// console.log(" - - - - RESPONSE: ")
// console.log(response.result);
t.equal(response.statusCode, 401, "Invalid token should error!");
t.end();
});
});
test("Auth mode 'optional' should pass with valid token", function(t) {
// use the token as the 'authorization' header in requests
// var token = JWT.sign({ id: 123, "name": "Charlie" }, secret);
var token = JWT.sign({ id: 123, "name": "Charlie" }, secret);
var options = {
method: "POST",
url: "/optional",
headers: { authorization: "Bearer " + token }
};
// server.inject lets us simulate an http request
server.inject(options, function(response) {
// console.log(" - - - - RESPONSE: ")
// console.log(response.result);
t.equal(response.statusCode, 200, "Valid token should succeed!");
t.end();
});
});
test("Auth mode 'try' should pass when no auth header specified", function(t) {
var options = {
method: "POST",
url: "/try"
};
server.inject(options, function(response) {
// console.log(" - - - - RESPONSE: ")
// console.log(response.result);
t.equal(response.statusCode, 200, "No auth header should pass in 'try' mode!");
t.end();
});
});
test("Auth mode 'try' should pass with invalid token", function(t) {
// use the token as the 'authorization' header in requests
var token = JWT.sign({ id: 123, "name": "Charlie" }, 'badsecret');
var options = {
method: "POST",
url: "/try",
headers: { authorization: "Bearer " + token }
};
// server.inject lets us simulate an http request
server.inject(options, function(response) {
// console.log(" - - - - RESPONSE: ")
// console.log(response.result);
t.equal(response.statusCode, 200, "Invalid token should pass in 'try' mode");
t.end();
});
});
test("Auth mode 'try' should pass with valid token", function(t) {
// use the token as the 'authorization' header in requests
var token = JWT.sign({ id: 123, "name": "Charlie" }, secret);
var options = {
method: "POST",
url: "/try",
headers: { authorization: "Bearer " + token }
};
// server.inject lets us simulate an http request
server.inject(options, function(response) {
// console.log(" - - - - RESPONSE: ")
// console.log(response);
t.equal(response.statusCode, 200, "Valid token should succeed!");
t.end();
});
});
test("Scheme should set token in request.auth.token", function(t) {
// use the token as the 'authorization' header in requests
var token = JWT.sign({ id: 123, "name": "Charlie" }, secret);
var options = {
method: "GET",
url: "/token",
headers: { authorization: "Bearer " + token }
};
// server.inject lets us simulate an http request
server.inject(options, function(response) {
// console.log(" - - - - RESPONSE: ")
// console.log(response.result);
t.equal(response.result, token, 'Token is accesible from handler');
t.end();
});
});
test.onFinish(function () {
server.stop(function(){});
})
var test = require('tape');
var Hapi = require('hapi');
var JWT = require('jsonwebtoken');
var secret = 'NeverShareYourSecret';
var keyDict = { 5678: secret };
var server = new Hapi.Server();
server.connection();
test('Full token payload (header + payload + signature) is available to key lookup function using completeToken option', function (t) {
server.register(require('../'), function (err) {
t.ifError(err, 'No error registering hapi-auth-jwt2 plugin');
server.auth.strategy('jwt', 'jwt', {
key: function (decoded, callback) {
var signatureKey = keyDict[decoded.header.x5t]; // Look dynamically for key based on JWT header field
return callback(null, signatureKey);
},
complete: true,
validateFunc: function (decoded, request, callback) {
return callback(null, true);
},
verifyOptions: {algorithms: ['HS256']}
});
server.route({
method: 'POST',
path: '/',
handler: function (request, reply) { return reply('Ok'); },
config: { auth: 'jwt' }
});
var options = {
method: 'POST',
url: '/',
headers: {Authorization: JWT.sign({ id: 1234 }, secret, { header: { x5t: 5678 } })} // set custom JWT header field "x5t"
};
server.inject(options, function (response) {
t.equal(response.statusCode, 200, 'Server returned 200 status');
t.end();
});
});
});
test.onFinish(function () {
server.stop(function(){});
})
var test = require('tape');
var JWT = require('jsonwebtoken');
var secret = 'NeverShareYourSecret';
var server = require('./basic_server.js');
var cookie_options = '; Max-Age=31536000;'; //' Expires=Mon, 18 Jul 2016 05:29:45 GMT; Secure; HttpOnly';
// var cookie_options = {
// ttl: 365 * 30 * 7 * 24 * 60 * 60 * 1000, // in the distant future ...
// encoding: 'none', // we already used JWT to encode
// isSecure: true, // warm & fuzzy feelings
// isHttpOnly: true, // prevent client alteration
// clearInvalid: false, // remove invalid cookies
// strictHeader: true // don't allow violations of RFC 6265
// }
test("Attempt to access restricted content using inVALID Cookie Token", function(t) {
var token = JWT.sign({ id: 123, "name": "Charlie" }, 'badsecret');
var options = {
method: "POST",
url: "/privado",
headers: { cookie: "token=" + token }
};
console.log(options);
server.inject(options, function(response) {
t.equal(response.statusCode, 401, "Invalid token should error!");
t.end();
});
});
test("Attempt to access restricted content with VALID Token but malformed Cookie", function(t) {
var token = JWT.sign({ id: 123, "name": "Charlie" }, secret);
var options = {
method: "POST",
url: "/privado",
headers: { cookie: token }
};
// server.inject lets us simulate an http request
server.inject(options, function(response) {
t.equal(response.statusCode, 400, "Valid Token but inVALID COOKIE should fial!");
t.end();
});
});
test("Access restricted content with VALID Token Cookie", function(t) {
var token = JWT.sign({ id: 123, "name": "Charlie" }, secret);
var options = {
method: "POST",
url: "/privado",
headers: { cookie: "token=" + token }
};
// server.inject lets us simulate an http request
server.inject(options, function(response) {
t.equal(response.statusCode, 200, "VALID COOKIE Token should succeed!");
t.end();
});
});
test("Access restricted content with VALID Token Cookie (With Options!)", function(t) {
var token = JWT.sign({ id: 123, "name": "Charlie" }, secret);
var options = {
method: "POST",
url: "/privado",
headers: { cookie: "token=" + token + cookie_options }
};
// console.log(' - - - - - - - - - - - - - - - OPTIONS:')
// console.log(options);
// server.inject lets us simulate an http request
server.inject(options, function(response) {
// console.log(' - - - - - - - - - - - - - - - response:')
// console.log(response);
t.equal(response.statusCode, 200, "VALID COOKIE Token (With Options!) should succeed!");
t.end();
});
});
/** Regressions Tests for https://github.com/dwyl/hapi-auth-jwt2/issues/65 **/
// supply valid Token Auth Header but invalid Cookie
// should succeed because Auth Header is first
test("Authorization Header should take precedence over any cookie", function(t) {
var token = JWT.sign({ id: 123, "name": "Charlie" }, secret);
var options = {
method: "POST",
url: "/privado",
headers: {
authorization: "Bearer " + token,
cookie: "token=malformed.token" + cookie_options
}
};
server.inject(options, function(response) {
// console.log(' - - - - - - - - - - - - - - - response:')
// console.log(response);
t.equal(response.statusCode, 200, "Ignores cookie when Auth Header is set");
t.end();
});
});
// valid google analytics cookie but invalid auth header token
// see: https://github.com/dwyl/hapi-auth-jwt2/issues/65#issuecomment-124791842
test("Valid Google Analytics cookie should be ignored", function(t) {
var GA = "gwcm=%7B%22expires%22%3Anull%2C%22clabel%22%3A%22SbNVCILRtFcQwcrE6gM%22%2C%22backoff%22%3A1437241242%7D; _ga=GA1.2.1363734468.1432273334";
var token = JWT.sign({ id: 123, "name": "Charlie" }, secret);
var options = {
method: "POST",
url: "/privado",
headers: {
authorization: "Bearer " + token,
cookie: GA
}
};
server.inject(options, function(response) {
t.equal(response.statusCode, 200, "Ignores Google Analytics Cookie");
t.end();
});
});
test("Valid Google Analytics cookie should be ignored (BAD Header Token)", function(t) {
var GA = "gwcm=%7B%22expires%22%3Anull%2C%22clabel%22%3A%22SbNVCILRtFcQwcrE6gM%22%2C%22backoff%22%3A1437241242%7D; _ga=GA1.2.1363734468.1432273334";
var token = JWT.sign({ id: 123, "name": "Charlie" }, 'invalid');
var options = {
method: "POST",
url: "/privado",
headers: {
authorization: "Bearer " + token,
cookie: GA
}
};
server.inject(options, function(response) {
t.equal(response.statusCode, 401, "Ignores GA but Invalid Auth Header still rejected");
t.end();
});
});
// Supply a VALID Token in Cookie A-N-D valid GA in Cookie!!
test("Valid Google Analytics cookie should be ignored (BAD Header Token)", function(t) {
var GA = "gwcm=%7B%22expires%22%3Anull%2C%22clabel%22%3A%22SbNVCILRtFcQwcrE6gM%22%2C%22backoff%22%3A1437241242%7D; _ga=GA1.2.1363734468.1432273334";
var token = JWT.sign({ id: 123, "name": "Charlie" }, secret);
var options = {
method: "POST",
url: "/privado",
headers: {
cookie: "token=" + token + '; ' + GA
}
};
server.inject(options, function(response) {
t.equal(response.statusCode, 200, "Valid Cookie Token Succeeds (Ignores GA)");
t.end();
});
});
test("Attempt to access restricted content with cookieKey=false", function(t) {
var token = JWT.sign({ id: 123, "name": "Charlie" }, secret);
var options = {
method: "POST",
url: "/privadonocookie",
headers: { cookie: "token=" + token }
};
// server.inject lets us simulate an http request
server.inject(options, function(response) {
t.equal(response.statusCode, 401, "Disabled cookie auth shouldn't accept valid token!");
t.end();
});
});
test("Attempt to access restricted content with cookieKey=''", function(t) {
var token = JWT.sign({ id: 123, "name": "Charlie" }, secret);
var options = {
method: "POST",
url: "/privadonocookie2",
headers: { cookie: "=" + token }
};
// server.inject lets us simulate an http request
server.inject(options, function(response) {
t.equal(response.statusCode, 400, "Disabled cookie auth shouldn't accept valid token!");
t.end();
});
});
var test = require('tape');
var JWT = require('jsonwebtoken');
var secret = 'NeverShareYourSecret';
var server = require('./custom_parameters_server.js');
var cookie_options = '; Max-Age=31536000;'; //' Expires=Mon, 18 Jul 2016 05:29:45 GMT; Secure; HttpOnly';
// Those tests are the same as cookie-test and url-token-test but with custom parameters in cookie or URL
test("Attempt to access restricted content using inVALID Cookie Token - custom parameters", function(t) {
var token = JWT.sign({ id: 123, "name": "Charlie" }, 'badsecret');
var options = {
method: "POST",
url: "/privado",
headers: { cookie: "customCookieKey=" + token }
};
console.log(options);
server.inject(options, function(response) {
t.equal(response.statusCode, 401, "Invalid token should error!");
t.end();
});
});
test("Attempt to access restricted content with VALID Token but malformed Cookie - custom parameters", function(t) {
var token = JWT.sign({ id: 123, "name": "Charlie" }, secret);
var options = {
method: "POST",
url: "/privado",
headers: { cookie: token }
};
// server.inject lets us simulate an http request
server.inject(options, function(response) {
t.equal(response.statusCode, 400, "Valid Token but inVALID COOKIE should fial!");
t.end();
});
});
test("Access restricted content with VALID Token Cookie - custom parameters", function(t) {
var token = JWT.sign({ id: 123, "name": "Charlie" }, secret);
var options = {
method: "POST",
url: "/privado",
headers: { cookie: "customCookieKey=" + token }
};
// server.inject lets us simulate an http request
server.inject(options, function(response) {
t.equal(response.statusCode, 200, "VALID COOKIE Token should succeed!");
t.end();
});
});
test("Access restricted content with VALID Token Cookie (With Options!) - custom parameters", function(t) {
var token = JWT.sign({ id: 123, "name": "Charlie" }, secret);
var options = {
method: "POST",
url: "/privado",
headers: { cookie: "customCookieKey=" + token + cookie_options }
};
// console.log(' - - - - - - - - - - - - - - - OPTIONS:')
// console.log(options);
// server.inject lets us simulate an http request
server.inject(options, function(response) {
// console.log(' - - - - - - - - - - - - - - - response:')
// console.log(response);
t.equal(response.statusCode, 200, "VALID COOKIE Token (With Options!) should succeed!");
t.end();
});
});
/** Regressions Tests for https://github.com/dwyl/hapi-auth-jwt2/issues/65 **/
// supply valid Token Auth Header but invalid Cookie
// should succeed because Auth Header is first
test("Authorization Header should take precedence over any cookie - custom parameters", function(t) {
var token = JWT.sign({ id: 123, "name": "Charlie" }, secret);
var options = {
method: "POST",
url: "/privado",
headers: {
authorization: "MyAuthScheme " + token,
cookie: "customCookieKey=malformed.token" + cookie_options
}
};
server.inject(options, function(response) {
// console.log(' - - - - - - - - - - - - - - - response:')
// console.log(response);
t.equal(response.statusCode, 200, "Ignores cookie when Auth Header is set");
t.end();
});
});
// valid google analytics cookie but invalid auth header token
// see: https://github.com/dwyl/hapi-auth-jwt2/issues/65#issuecomment-124791842
test("Valid Google Analytics cookie should be ignored - custom parameters", function(t) {
var GA = "gwcm=%7B%22expires%22%3Anull%2C%22clabel%22%3A%22SbNVCILRtFcQwcrE6gM%22%2C%22backoff%22%3A1437241242%7D; _ga=GA1.2.1363734468.1432273334";
var token = JWT.sign({ id: 123, "name": "Charlie" }, secret);
var options = {
method: "POST",
url: "/privado",
headers: {
authorization: "MyAuthScheme " + token,
cookie: GA
}
};
server.inject(options, function(response) {
t.equal(response.statusCode, 200, "Ignores Google Analytics Cookie");
t.end();
});
});
test("Valid Google Analytics cookie should be ignored (BAD Header Token) - custom parameters", function(t) {
var GA = "gwcm=%7B%22expires%22%3Anull%2C%22clabel%22%3A%22SbNVCILRtFcQwcrE6gM%22%2C%22backoff%22%3A1437241242%7D; _ga=GA1.2.1363734468.1432273334";
var token = JWT.sign({ id: 123, "name": "Charlie" }, 'invalid');
var options = {
method: "POST",
url: "/privado",
headers: {
authorization: "MyAuthScheme " + token,
cookie: GA
}
};
server.inject(options, function(response) {
t.equal(response.statusCode, 401, "Ignores GA but Invalid Auth Header still rejected");
t.end();
});
});
// Supply a VALID Token in Cookie A-N-D valid GA in Cookie!!
test("Valid Google Analytics cookie should be ignored (BAD Header Token) - custom parameters", function(t) {
var GA = "gwcm=%7B%22expires%22%3Anull%2C%22clabel%22%3A%22SbNVCILRtFcQwcrE6gM%22%2C%22backoff%22%3A1437241242%7D; _ga=GA1.2.1363734468.1432273334";
var token = JWT.sign({ id: 123, "name": "Charlie" }, secret);
var options = {
method: "POST",
url: "/privado",
headers: {
cookie: "customCookieKey=" + token + '; ' + GA
}
};
server.inject(options, function(response) {
t.equal(response.statusCode, 200, "Valid Cookie Token Succeeds (Ignores GA)");
t.end();
});
});
test("Attempt to access restricted content (with an INVALID URL Token) - custom parameters", function(t) {
var token = "?customUrlKey=my.invalid.token";
var options = {
method: "POST",
url: "/privado" + token
};
// server.inject lets us simulate an http request
server.inject(options, function(response) {
t.equal(response.statusCode, 401, "INVALID Token should fail");
t.end();
});
});
test("Try using an incorrect secret to sign the JWT - custom parameters", function(t) {
// use the token as the 'authorization' header in requests
var token = JWT.sign({ id: 123, "name": "Charlie" }, 'incorrectSecret');
token = "?customUrlKey=" + token;
// console.log(" - - - - - - token - - - - -")
// console.log(token);
var options = {
method: "POST",
url: "/privado" + token
};
// server.inject lets us simulate an http request
server.inject(options, function(response) {
t.equal(response.statusCode, 401, "URL Token signed with incorrect key fails");
t.end();
});
});
test("URL Token is well formed but is allowed=false so should be denied - custom parameters", function(t) {
// use the token as the 'authorization' header in requests
// var token = jwt.sign({ "id": 1 ,"name":"Old Greg" }, 'incorrectSecret');
var token = JWT.sign({ id: 321, "name": "Old Gregg" }, secret);
token = "?customUrlKey=" + token;
var options = {
method: "POST",
url: "/privado" + token
};
// server.inject lets us simulate an http request
server.inject(options, function(response) {
t.equal(response.statusCode, 401, "User is Denied");
t.end();
});
});
test("Access restricted content (with VALID Token) - custom parameters", function(t) {
// use the token as the 'authorization' header in requests
var token = JWT.sign({ id: 123, "name": "Charlie" }, secret);
token = "?customUrlKey=" + token;
var options = {
method: "POST",
url: "/privado" + token
};
// server.inject lets us simulate an http request
server.inject(options, function(response) {
t.equal(response.statusCode, 200, "VALID Token should succeed!");
t.end();
});
});
test("Attempt to access restricted content using inVALID header tokenType - custom parameters", function(t) {
var token = JWT.sign({ id: 123, "name": "Charlie" }, 'badsecret');
var options = {
method: "POST",
url: "/privado",
headers: { Authorization: "InvalidAuthScheme " + token }
};
server.inject(options, function(response) {
t.equal(response.statusCode, 401, "Invalid token should error!");
t.end();
});
});
test("Access restricted content (with VALID Token and header tokenType) - custom parameters", function(t) {
var token = JWT.sign({ id: 123, "name": "Charlie" }, secret);
var options = {
method: "POST",
url: "/privado",
headers: { Authorization: "MyAuthScheme " + token }
};
server.inject(options, function(response) {
t.equal(response.statusCode, 200, "VALID Token should succeed!");
t.end();
});
});
var test = require('tape');
var Hapi = require('hapi');
var JWT = require('jsonwebtoken');
var secret = 'NeverShareYourSecret';
var keyDict = { 5678: secret };
test('When using a custom header key full token payload (header + payload + signature) is available to key lookup function using completeToken option', function (t) {
var server = new Hapi.Server();
server.connection();
server.register(require('../'), function (err) {
t.ifError(err, 'No error registering hapi-auth-jwt2 plugin');
server.auth.strategy('jwt', 'jwt', {
key: function (decoded, callback) {
var signatureKey = keyDict[decoded.header.x5t]; // Look dynamically for key based on JWT header field
return callback(null, signatureKey);
},
complete: true,
validateFunc: function (decoded, request, callback) {
return callback(null, true);
},
verifyOptions: {algorithms: ['HS256']},
headerKey: 'auths'
});
server.route({
method: 'POST',
path: '/',
handler: function (request, reply) { return reply('Ok'); },
config: { auth: 'jwt' }
});
var options = {
method: 'POST',
url: '/',
headers: {auths: JWT.sign({ id: 1234 }, secret, { header: { x5t: 5678 } })} // set custom JWT header field "x5t"
};
server.inject(options, function (response) {
t.equal(response.statusCode, 200, 'Server returned 200 status');
t.end();
});
});
});
var test = require('tape');
var JWT = require('jsonwebtoken');
var server = require('./dynamic_key_server'); // test server which in turn loads our module
test("Access restricted content with a valid token and tenant", function(t) {
// use the token as the 'authorization' header in requests
var token = JWT.sign({ id: 123, "name": "Charlie", "tenant": "dunderMifflin" }, 'michaelscott');
var options = {
method: "POST",
url: "/privado",
headers: { authorization: "Bearer " + token }
};
// server.inject lets us simulate an http request
server.inject(options, function(response) {
console.log(" - - - - RESPONSE: ");
console.log(response.result);
t.equal(response.statusCode, 200, "VALID Token should succeed!");
t.equal(response.result.data.additional, 'something extra here if needed', 'extraInfo should be passed through');
t.end();
});
});
test("Access restricted content with an invalid token and tenant", function(t) {
// use the token as the 'authorization' header in requests
var token = JWT.sign({ id: 123, "name": "Charlie", "tenant": "dunderMifflin" }, 'dwightschrute');
var options = {
method: "POST",
url: "/privado",
headers: { authorization: "Bearer " + token }
};
// server.inject lets us simulate an http request
server.inject(options, function(response) {
console.log(" - - - - RESPONSE: ");
console.log(response.result);
t.equal(response.statusCode, 401, "INVALID Token should fail!");
t.end();
});
});
test("Access restricted content with a valid token and tenant but user is not allowed", function(t) {
// use the token as the 'authorization' header in requests
var token = JWT.sign({ id: 321, "name": "Old Gregg", "tenant": "wernhamHogg" }, 'davidbrent');
var options = {
method: "POST",
url: "/privado",
headers: { authorization: "Bearer " + token }
};
// server.inject lets us simulate an http request
server.inject(options, function(response) {
console.log(" - - - - RESPONSE: ");
console.log(response.result);
t.equal(response.statusCode, 401, "Not allowed user should fail!");
t.end();
});
});
test("Access restricted content without tenant specified in token", function(t) {
// use the token as the 'authorization' header in requests
var token = JWT.sign({ id: 123, "name": "Charlie" }, 'michaelscott');
var options = {
method: "POST",
url: "/privado",
headers: { authorization: "Bearer " + token }
};
// server.inject lets us simulate an http request
server.inject(options, function(response) {
console.log(" - - - - RESPONSE: ");
console.log(response.result);
t.equal(response.statusCode, 400, "No tenant specified should fail!");
t.end();
});
});
test("Access restricted content with non-existent tenant specified", function(t) {
// use the token as the 'authorization' header in requests
var token = JWT.sign({ id: 123, "name": "Charlie", "tenant": "princeFamilyPaper" }, 'michaelscott');
var options = {
method: "POST",
url: "/privado",
headers: { authorization: "Bearer " + token }
};
// server.inject lets us simulate an http request
server.inject(options, function(response) {
console.log(" - - - - RESPONSE: ");
console.log(response.result);
t.equal(response.statusCode, 401, "No tentant found should fail!");
t.end();
});
});
var test = require('tape');
var JWT = require('jsonwebtoken');
// var secret = 'NeverShareYourSecret';
var server = require('./error_func_server'); // test server which in turn loads our module
test("Access a route that has no auth strategy", function(t) {
var options = {
method: "GET",
url: "/"
};
// server.inject lets us simulate an http request
server.inject(options, function(response) {
t.equal(response.statusCode, 200, "GET / still works without token.");
t.end();
});
});
test("customVerify simulate error condition", function(t) {
var payload = { id: 123, "name": "Charlie", error: true }
var token = JWT.sign(payload, 'SecretDoesNOTGetVerified');
var options = {
method: "GET",
url: "/required",
headers: { authorization: "Bearer " + token }
};
// server.inject lets us simulate an http request
server.inject(options, function(response) {
t.equal(response.statusCode, 500, "customVerify force error");
t.equal(response.result.message, "An internal server error occurred", "GET /required with forced error that has not been customised");
t.end();
});
});
test("customVerify simulate error condition but is safely not customised", function(t) {
var payload = { id: 123, "name": "Charlie", custom_error: 'ignore'}
var token = JWT.sign(payload, 'SecretDoesNOTGetVerified');
var options = {
method: "GET",
url: "/required",
headers: { authorization: "Bearer " + token }
};
// server.inject lets us simulate an http request
server.inject(options, function(response) {
t.equal(response.statusCode, 500, "customVerify force error");
t.equal(response.result.message, "An internal server error occurred", "GET /required with forced error that has not been customised");
t.end();
});
});
test("customVerify with fail condition", function(t) {
var payload = { id: 123, "name": "Charlie", some_property: false }
var token = JWT.sign(payload, 'SecretDoesNOTGetVerified');
var options = {
method: "GET",
url: "/required",
headers: { authorization: "Bearer " + token }
};
// server.inject lets us simulate an http request
server.inject(options, function(response) {
t.equal(response.statusCode, 401, "GET /required with customVerify rejected");
t.equal(response.result.message, "Invalid credentials mate", "GET /required with customVerify rejected and customised error message");
t.end();
});
});
test("Custom Verification in 'try' mode ", function(t) {
var payload = { id: 123, "name": "Charlie", some_property: true }
var token = JWT.sign(payload, 'SecretDoesNOTGetVerified');
var options = {
method: "GET",
url: "/try",
headers: { authorization: "Bearer " + token }
};
// server.inject lets us simulate an http request
server.inject(options, function(response) {
t.equal(response.result.id, payload.id, 'Decoded JWT returned by handler');
t.equal(response.statusCode, 200, "GET /try bypasses verification");
t.end();
});
});
test("Custom Verification in 'optional' mode ", function(t) {
var payload = { id: 234, "name": "Oscar", some_property: true }
var token = JWT.sign(payload, 'SecretDoesNOTGetVerified');
var options = {
method: "GET",
url: "/optional",
headers: { authorization: "Bearer " + token }
};
// server.inject lets us simulate an http request
server.inject(options, function(response) {
t.equal(response.result.id, payload.id, 'Decoded JWT returned by handler');
t.equal(response.statusCode, 200, "GET /optional bypasses verification");
t.end();
});
});
test("Custom Verification in 'required' mode ", function(t) {
var payload = { id: 345, "name": "Romeo", some_property: true }
var token = JWT.sign(payload, 'AnyStringWillDo');
var options = {
method: "GET",
url: "/required",
headers: { authorization: "Bearer " + token }
};
// server.inject lets us simulate an http request
server.inject(options, function(response) {
// console.log(response.result);
var credentials = JSON.parse(JSON.stringify(response.result));
t.equal(credentials.id, payload.id, 'Decoded JWT is available in handler');
t.equal(response.statusCode, 200, "GET /required bypasses verification");
t.end();
});
});
var test = require('tape');
var JWT = require('jsonwebtoken');
var secret = 'NeverShareYourSecret';
var server = require('./scheme-response-server'); // test server which in turn loads our module
test("Attempt to access restricted content (without auth token)", function(t) {
var options = {
method: "POST",
url: "/privado"
};
server.inject(options, function(response) {
t.equal(response.statusCode, 401, "No Token should fail");
t.equal(response.headers.authorization, undefined, 'Invalid requests should not be calling the response function');
t.end();
});
});
test("Attempt to access restricted content (with an INVALID Token)", function(t) {
var options = {
method: "POST",
url: "/privado",
headers: { authorization: "Bearer fails.validation" }
};
server.inject(options, function(response) {
t.equal(response.statusCode, 401, "INVALID Token should fail");
t.equal(response.headers.authorization, undefined, 'Invalid requests should not be calling the response function');
t.end();
});
});
test("Access restricted content (with VALID Token)", function(t) {
// use the token as the 'authorization' header in requests
var token = JWT.sign({ id: 123, "name": "Charlie" }, secret);
var options = {
method: "POST",
url: "/privado",
headers: { authorization: "Bearer " + token }
};
server.inject(options, function(response) {
t.equal(response.statusCode, 200, "VALID Token should succeed!");
t.equal(response.headers.authorization, 'from scheme response function', 'Valid request should finish by calling response function');
t.end();
});
});
test("Auth mode 'required' should require authentication header", function(t) {
var options = {
method: "POST",
url: "/required"
};
server.inject(options, function(response) {
t.equal(response.statusCode, 401, "No token header should fail in auth 'required' mode");
t.equal(response.headers.authorization, undefined, 'Invalid requests should not be calling the response function');
t.end();
});
});
test("Auth mode 'required' should should pass with valid token", function(t) {
// use the token as the 'authorization' header in requests
var token = JWT.sign({ id: 123, "name": "Charlie" }, secret);
var options = {
method: "POST",
url: "/required",
headers: { authorization: "Bearer " + token }
};
server.inject(options, function(response) {
t.equal(response.statusCode, 200, "Valid token should succeed!");
t.equal(response.headers.authorization, 'from scheme response function', 'Valid request should finish by calling response function');
t.end();
});
});
test("Scheme should set token in request.auth.token", function(t) {
// use the token as the 'authorization' header in requests
var token = JWT.sign({ id: 123, "name": "Charlie" }, secret);
var options = {
method: "GET",
url: "/token",
headers: { authorization: "Bearer " + token }
};
server.inject(options, function(response) {
t.equal(response.result, token, 'Token is accesible from handler');
t.equal(response.headers.authorization, 'from scheme response function', 'Valid request should finish by calling response function');
t.end();
});
});
test("Testing an error thrown from the scheme\'s response function", function(t) {
// use the token as the 'authorization' header in requests
var token = JWT.sign({ id: 123, "name": "Charlie" }, secret);
var options = {
method: "GET",
url: "/token",
headers: {
authorization: "Bearer " + token,
error: 'true'
}
};
// server.inject lets us simulate an http request
server.inject(options, function(response) {
t.equal(response.statusCode, 500, 'A server error happens in the scheme\'s response function');
t.end();
});
});
var test = require('tape');
var JWT = require('jsonwebtoken');
var secret = 'NeverShareYourSecret'; // set by ENV Variable
var server = require('./scopes_server'); // test server which in turn loads our module
test("Access restricted content using scopes (with VALID Token and VALID scope)", function(t) {
// use the token as the 'authorization' header in requests
var token = JWT.sign({ id: 123, "name": "Charlie" }, secret);
var options = {
method: "POST",
url: "/privado-with-scope",
headers: { authorization: "Bearer " + token }
};
// server.inject lets us simulate an http request
server.inject(options, function(response) {
console.log(" - - - - RESPONSE: ");
console.log(response.result);
t.equal(response.statusCode, 200, "VALID Token should succeed!");
t.end();
});
});
test("Access restricted content using scopes (with VALID Token and INVALID scope)", function(t) {
// use the token as the 'authorization' header in requests
var token = JWT.sign({ id: 321, "name": "Old Gregg" }, secret);
var options = {
method: "POST",
url: "/privado-with-scope",
headers: { authorization: "Bearer " + token }
};
// server.inject lets us simulate an http request
server.inject(options, function(response) {
console.log(" - - - - RESPONSE: ");
console.log(response.result);
t.equal(response.statusCode, 401, "Denied");
t.end();
});
});
var test = require('tape');
var JWT = require('jsonwebtoken');
var secret = 'NeverShareYourSecret';
var server = require('./basic_server.js');
test("Attempt to access restricted content (without auth token)", function(t) {
var options = {
method: "POST",
url: "/privado"
};
// server.inject lets us simulate an http request
server.inject(options, function(response) {
t.equal(response.statusCode, 401, "No Token supplied > fails (as expected)");
t.end();
});
});
test("Attempt to access restricted content (with an INVALID URL Token)", function(t) {
var token = "?token=my.invalid.token";
var options = {
method: "POST",
url: "/privado" + token
};
// server.inject lets us simulate an http request
server.inject(options, function(response) {
t.equal(response.statusCode, 401, "INVALID Token should fail");
t.end();
});
});
test("Try using an incorrect secret to sign the JWT", function(t) {
// use the token as the 'authorization' header in requests
var token = JWT.sign({ id: 123, "name": "Charlie" }, 'incorrectSecret');
token = "?token=" + token;
// console.log(" - - - - - - token - - - - -")
// console.log(token);
var options = {
method: "POST",
url: "/privado" + token
};
// server.inject lets us simulate an http request
server.inject(options, function(response) {
t.equal(response.statusCode, 401, "URL Token signed with incorrect key fails");
t.end();
});
});
test("URL Token is well formed but is allowed=false so should be denied", function(t) {
// use the token as the 'authorization' header in requests
// var token = jwt.sign({ "id": 1 ,"name":"Old Greg" }, 'incorrectSecret');
var token = JWT.sign({ id: 321, "name": "Old Gregg" }, secret);
token = "?token=" + token;
var options = {
method: "POST",
url: "/privado" + token
};
// server.inject lets us simulate an http request
server.inject(options, function(response) {
t.equal(response.statusCode, 401, "User is Denied");
t.end();
});
});
test("Access restricted content (with VALID Token)", function(t) {
// use the token as the 'authorization' header in requests
var token = JWT.sign({ id: 123, "name": "Charlie" }, secret);
token = "?token=" + token;
var options = {
method: "POST",
url: "/privado" + token
};
// server.inject lets us simulate an http request
server.inject(options, function(response) {
t.equal(response.statusCode, 200, "VALID Token should succeed!");
t.end();
});
});
test("Using route with urlKey=false should be denied", function(t) {
// use the token as the 'authorization' header in requests
var token = JWT.sign({ id: 123, "name": "Charlie" }, secret);
token = "?token=" + token;
var options = {
method: "POST",
url: "/privadonourl" + token
};
// server.inject lets us simulate an http request
server.inject(options, function(response) {
t.equal(response.statusCode, 401, "No urlKey configured so URL-Tokens should be denied");
t.end();
});
});
test("Using route with urlKey='' should be denied", function(t) {
// use the token as the 'authorization' header in requests
var token = JWT.sign({ id: 123, "name": "Charlie" }, secret);
token = "?=" + token;
var options = {
method: "POST",
url: "/privadonourl2" + token
};
// server.inject lets us simulate an http request
server.inject(options, function(response) {
t.equal(response.statusCode, 401, "No urlKey configured so URL-Tokens should be denied");
t.end();
});
});
var test = require('tape');
var Hapi = require('hapi');
var JWT = require('jsonwebtoken');
var secret = 'NeverShareYourSecret';
test('Should respond with 500 series error when validateFunc errs', function (t) {
var server = new Hapi.Server();
server.connection();
server.register(require('../'), function (err) {
t.ifError(err, 'No error registering hapi-auth-jwt2 plugin');
server.auth.strategy('jwt', 'jwt', {
key: secret,
validateFunc: function (decoded, request, callback) {
return callback(new Error('ASPLODE'));
},
verifyOptions: {algorithms: ['HS256']}
});
server.route({
method: 'POST',
path: '/privado',
handler: function (req, reply) { return reply('PRIVADO'); },
config: { auth: 'jwt' }
});
var options = {
method: 'POST',
url: '/privado',
headers: {Authorization: JWT.sign({id: 138, name: 'Test'}, secret)}
};
server.inject(options, function (response) {
t.equal(response.statusCode, 500, 'Server returned 500 for validateFunc error');
t.end();
});
});
});
var test = require('tape');
var JWT = require('jsonwebtoken');
// var secret = 'NeverShareYourSecret';
var server = require('./verify_func_server'); // test server which in turn loads our module
test("Access a route that has no auth strategy", function(t) {
var options = {
method: "GET",
url: "/"
};
// server.inject lets us simulate an http request
server.inject(options, function(response) {
t.equal(response.statusCode, 200, "GET / still works without token.");
t.end();
});
});
test("customVerify simulate error condition", function(t) {
var payload = { id: 123, "name": "Charlie", error: true }
var token = JWT.sign(payload, 'SecretDoesNOTGetVerified');
var options = {
method: "GET",
url: "/required",
headers: { authorization: "Bearer " + token }
};
// server.inject lets us simulate an http request
server.inject(options, function(response) {
t.equal(response.statusCode, 500, "customVerify force error");
t.end();
});
});
test("customVerify with fail condition", function(t) {
var payload = { id: 123, "name": "Charlie", some_property: false }
var token = JWT.sign(payload, 'SecretDoesNOTGetVerified');
var options = {
method: "GET",
url: "/required",
headers: { authorization: "Bearer " + token }
};
// server.inject lets us simulate an http request
server.inject(options, function(response) {
t.equal(response.statusCode, 401, "GET /required with customVerify rejected");
t.end();
});
});
test("Custom Verification in 'try' mode ", function(t) {
var payload = { id: 123, "name": "Charlie", some_property: true }
var token = JWT.sign(payload, 'SecretDoesNOTGetVerified');
var options = {
method: "GET",
url: "/try",
headers: { authorization: "Bearer " + token }
};
// server.inject lets us simulate an http request
server.inject(options, function(response) {
t.equal(response.result.id, payload.id, 'Decoded JWT returned by handler');
t.equal(response.statusCode, 200, "GET /try bypasses verification");
t.end();
});
});
test("Custom Verification in 'optional' mode ", function(t) {
var payload = { id: 234, "name": "Oscar", some_property: true }
var token = JWT.sign(payload, 'SecretDoesNOTGetVerified');
var options = {
method: "GET",
url: "/optional",
headers: { authorization: "Bearer " + token }
};
// server.inject lets us simulate an http request
server.inject(options, function(response) {
t.equal(response.result.id, payload.id, 'Decoded JWT returned by handler');
t.equal(response.statusCode, 200, "GET /optional bypasses verification");
t.end();
});
});
test("Custom Verification in 'required' mode ", function(t) {
var payload = { id: 345, "name": "Romeo", some_property: true }
var token = JWT.sign(payload, 'AnyStringWillDo');
var options = {
method: "GET",
url: "/required",
headers: { authorization: "Bearer " + token }
};
// server.inject lets us simulate an http request
server.inject(options, function(response) {
// console.log(response.result);
var credentials = JSON.parse(JSON.stringify(response.result));
t.equal(credentials.id, payload.id, 'Decoded JWT is available in handler');
t.equal(response.statusCode, 200, "GET /required bypasses verification");
t.end();
});
});
+8
-6

@@ -51,8 +51,10 @@ var Boom = require('boom'); // error handling https://github.com/hapijs/boom

var tokenType = options.tokenType || 'Token'; //
if (!token) {
return reply(raiseError('unauthorized', null, 'Token'));
return reply(raiseError('unauthorized', null, tokenType));
}
if (!extract.isValid(token)) { // quick check for validity of token format
return reply(raiseError('unauthorized', 'Invalid token format', 'Token'));
return reply(raiseError('unauthorized', 'Invalid token format', tokenType));
} // verification is done later, but we want to avoid decoding if malformed

@@ -66,3 +68,3 @@ request.auth.token = token; // keep encoded JWT available in the request lifecycle

catch(e) { // request should still FAIL if the token does not decode.
return reply(raiseError('unauthorized', 'Invalid token format', 'Token'));
return reply(raiseError('unauthorized', 'Invalid token format', tokenType));
}

@@ -84,3 +86,3 @@

if (err) {
return reply(raiseError('unauthorized', 'Invalid token', 'Token'), null, { credentials: null });
return reply(raiseError('unauthorized', 'Invalid token', tokenType), null, { credentials: null });
}

@@ -93,3 +95,3 @@ else { // see: http://hapijs.com/tutorials/auth for validateFunc signature

else if (!valid) {
return reply(raiseError('unauthorized', 'Invalid credentials', 'Token'), null, { credentials: credentials || decoded });
return reply(raiseError('unauthorized', 'Invalid credentials', tokenType), null, { credentials: credentials || decoded });
}

@@ -110,3 +112,3 @@ else {

else if (!valid) {
return reply(raiseError('unauthorized', 'Invalid credentials', 'Token'), null, { credentials: decoded });
return reply(raiseError('unauthorized', 'Invalid credentials', tokenType), null, { credentials: decoded });
} else {

@@ -113,0 +115,0 @@ return reply.continue({ credentials: credentials, artifacts: token });

{
"name": "hapi-auth-jwt2",
"version": "7.1.0",
"version": "7.1.1",
"description": "Hapi.js Authentication Plugin/Scheme using JSON Web Tokens (JWT)",

@@ -42,14 +42,14 @@ "main": "lib/index.js",

"dependencies": {
"boom": "^3.1.3",
"boom": "^3.2.2",
"cookie": "^0.3.1",
"jsonwebtoken": "^7.0.0"
"jsonwebtoken": "^7.1.9"
},
"devDependencies": {
"aguid": "^1.0.4",
"hapi": "^13.4.1",
"istanbul": "^0.4.3",
"jshint": "^2.9.2",
"hapi": "^14.2.0",
"istanbul": "^0.4.5",
"jshint": "^2.9.3",
"pre-commit": "^1.1.3",
"tap-spec": "^4.1.1",
"tape": "^4.5.1"
"tape": "^4.6.0"
},

@@ -60,5 +60,5 @@ "engines": {

"scripts": {
"quick": "./node_modules/tape/bin/tape ./test/*.js | node_modules/tap-spec/bin/cmd.js",
"test": "istanbul cover ./node_modules/tape/bin/tape ./test/*.js | node_modules/tap-spec/bin/cmd.js",
"coverage": "istanbul cover ./node_modules/tape/bin/tape ./test/*.js && istanbul check-coverage --statements 100 --functions 100 --lines 100 --branches 100",
"quick": "./node_modules/tape/bin/tape ./test/*.test.js | node_modules/tap-spec/bin/cmd.js",
"test": "istanbul cover ./node_modules/tape/bin/tape ./test/*.test.js | node_modules/tap-spec/bin/cmd.js",
"coverage": "istanbul cover ./node_modules/tape/bin/tape ./test/*.test.js && istanbul check-coverage --statements 100 --functions 100 --lines 100 --branches 100",
"jshint": "./node_modules/jshint/bin/jshint -c .jshintrc --exclude-path .gitignore .",

@@ -65,0 +65,0 @@ "start": "node example/server.js",

+89
-16

@@ -11,10 +11,7 @@ # Hapi Auth using JSON Web Tokens (JWT)

[![Code Climate](https://codeclimate.com/github/dwyl/hapi-auth-jwt2/badges/gpa.svg "No Nasty Code")](https://codeclimate.com/github/dwyl/hapi-auth-jwt2)
[![HAPI 13.4.1](http://img.shields.io/badge/hapi-13.4.1-brightgreen.svg "Latest Hapi.js")](http://hapijs.com)
[![HAPI 14.2.0](http://img.shields.io/badge/hapi-14.2.0-brightgreen.svg "Latest Hapi.js")](http://hapijs.com)
[![Node.js Version](https://img.shields.io/node/v/hapi-auth-jwt2.svg?style=flat "Node.js 10 & 12 and io.js latest both supported")](http://nodejs.org/download/)
[![npm](https://img.shields.io/npm/v/hapi-auth-jwt2.svg)](https://www.npmjs.com/package/hapi-auth-jwt2)
[![Dependency Status](https://david-dm.org/dwyl/hapi-auth-jwt2.svg "Dependencies Checked & Updated Regularly (Security is Important!)")](https://david-dm.org/dwyl/hapi-auth-jwt2)
[![devDependency Status](https://david-dm.org/dwyl/hapi-auth-jwt2/dev-status.svg)](https://david-dm.org/dwyl/hapi-auth-jwt2#info=devDependencies)
[![bitHound Score](https://www.bithound.io/github/dwyl/hapi-auth-jwt2/badges/score.svg)](https://www.bithound.io/github/dwyl/hapi-auth-jwt2)
[![Join the chat at https://gitter.im/dwyl/chat](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/dwyl/chat/?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[![devDependencies Status](https://david-dm.org/dwyl/hapi-auth-jwt2/dev-status.svg)](https://david-dm.org/dwyl/hapi-auth-jwt2?type=dev)
[![npm package version](https://img.shields.io/npm/v/hapi-auth-jwt2.svg)](https://www.npmjs.com/package/hapi-auth-jwt2)

@@ -205,3 +202,11 @@ This node.js module (Hapi plugin) lets you use JSON Web Tokens (JWTs)

### Useful Features
+ The *encoded* JWT (token) is extracted from the headers of the request and
made available on the `request` object as `request.auth.token`,
in case you need it later on in the request lifecycle.
This feature was requested by @mcortesi in
[hapi-auth-jwt2/issues/123](https://github.com/dwyl/hapi-auth-jwt2/issues/123)
### Understanding the Request Flow

@@ -368,3 +373,3 @@

### Background Reading
#### Background Reading (*Cookies*)

@@ -379,7 +384,9 @@ + Wikipedia has a good intro (general): https://en.wikipedia.org/wiki/HTTP_cookie

## Frequently Asked Questions (FAQ)
## Frequently Asked Questions (FAQ) [![Join the chat at https://gitter.im/dwyl/chat](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/dwyl/chat/?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
1. Do I need to include **jsonwebtoken** in my project? asked in [hapi-auth-jwt2/issues/32](https://github.com/dwyl/hapi-auth-jwt2/issues/32)
### Do I *need* to include `jsonwebtoken` in my project?
**Q**: Must I include the **jsonwebtoken** package in my project
[given that **hapi-auth-jwt2** plugin already includes it] ?
[given that **hapi-auth-jwt2** plugin already includes it] ? asked in [hapi-auth-jwt2/issues/32](https://github.com/dwyl/hapi-auth-jwt2/issues/32)
**A**: Yes, you need to *manually* install the **jsonwebtoken**

@@ -393,3 +400,5 @@ node module from NPM with `npm install jsonwebtoken --save` if you want to ***sign*** JWTs in your app.

2. Can we supply a ***Custom Verification*** function instead of using the **JWT.verify** method?
### ***Custom Verification*** ?
Can we supply a ***Custom Verification*** function instead of using the **JWT.verify** method?
asked by *both* [Marcus Stong](https://github.com/stongo) & [Kevin Stewart](https://github.com/kdstew)

@@ -401,3 +410,70 @@ in [issue #120](https://github.com/dwyl/hapi-auth-jwt2/issues/120) and [issue #130](https://github.com/dwyl/hapi-auth-jwt2/issues/130) respectively.

<br />
### Can I use `hapi-auth-jwt2` with [`glue`](https://github.com/hapijs/glue)
Several people asked us if this plugin is compatible with
Hapi's "Server Composer" [`glue`](https://github.com/hapijs/glue)
The answer is ***Yes***! For an example of how to do this,
see [@avanslaars](https://github.com/avanslaars) code example:
https://github.com/dwyl/hapi-auth-jwt2/issues/151#issuecomment-218321212
<br />
### How do I *invalidate* an *existing token*?
Asked by [@SanderElias](https://github.com/SanderElias) in [hapi-auth-jwt2/issues/126](https://github.com/dwyl/hapi-auth-jwt2/issues/126)
We store our JWT-based sessions in a Redis datastore and lookup the session (`jti`) for the given JWT during the `validateFunc` (*validation function*) see: https://github.com/dwyl/hapi-auth-jwt2-example/blob/791b0d3906d4deb256daf23fcf8f5021905abe9e/index.js#L25
This means we can invalidate the session in Redis and then reject a request that uses an "old" or invalid JWT. see: https://github.com/dwyl/hapi-auth-jwt2-example/blob/791b0d3906d4deb256daf23fcf8f5021905abe9e/index.js#L25
<br />
### How do I set JWT Auth to *All Routes*?
[@abeninskibede](https://github.com/abeninskibede) asked how to set all routes to use JWT Auth in [hapi-auth-jwt2/issues/149](https://github.com/dwyl/hapi-auth-jwt2/issues/149)
We tend to enable `hapi-auth-jwt2` for _all_ routes by setting the `mode` parameter to `true` (so its `required` for all endpoints) because _most_ of the endpoints in our app require the person/user to be authenticated e.g:
```js
// setting the 3rd argument to true means 'mode' is 'required' see: http://hapijs.com/tutorials/auth#mode
server.auth.strategy('jwt', 'jwt', true, { // so JWT auth is required for all routes
key: process.env.JWT_SECRET,
validateFunc: require('./jwt2_validate_func'),
verifyOptions: { ignoreExpiration: true, algorithms: [ 'HS256' ] }
});
```
> _Detailed Practical Example_: https://github.com/dwyl/hapi-login-example-postgres/blob/245a44f0e88226d99a3ad2e3dc38cc0d1750a241/lib/server.js#L33
When you want a particular route to ***not require*** JWT auth you simply set `config: { auth: false }` e.g:
```js
server.route({
method: 'GET',
path: '/login',
handler: login_handler, // display login/registration form/page
config: { auth: false } // don't require people to be logged in to see the login page! (duh!)
});
```
The best place to _understand_ everything about Hapi Auth is in the docs: http://hapijs.com/tutorials/auth#setting-a-default-strategy
But if you have any questions which are not answered there, feel free to [ask!](https://github.com/dwyl/hapi-auth-jwt2/issues)
<br />
### How to _redirect_ if a token has expired?
@traducer & @goncalvesr2 both requested how to redirect after failed Auth in
[hapi-auth-jwt2/issues/161](https://github.com/dwyl/hapi-auth-jwt2/issues/161)
and [hapi-auth-jwt2/issues/148](https://github.com/dwyl/hapi-auth-jwt2/issues/148) respectively
The [`hapi-error`](https://github.com/dwyl/hapi-error) lets
you _easily_ redirect to any url you define if the Auth check fails
(i.e. `statusCode 401`)
see: https://github.com/dwyl/hapi-error#redirecting-to-another-endpoint
(*code examples there.*)
<br />
## *Advanced/Alternative* Usage => Bring Your Own `verifyFunc`

@@ -439,7 +515,4 @@

`hapi-auth-jwt2` is compatible with Hapi.js versions `11.x.x` `10.x.x` `9.x.x` and `8.x.x` as there was no change to how the Hapi plugin system works
for the past two versions.
See the release notes for more details:
+ Hapi Version 10: https://github.com/hapijs/hapi/issues/2764
+ Hapi Version 9: https://github.com/hapijs/hapi/issues/2682
`hapi-auth-jwt2` is compatible with Hapi.js versions `14.x.x` `13.x.x` `12.x.x` `11.x.x` `10.x.x` `9.x.x` and `8.x.x`
as there have been ***no changes*** to how the Hapi plugin system works for a while!

@@ -446,0 +519,0 @@ However in the interest of

var test = require('tape');
var JWT = require('jsonwebtoken');
var secret = 'NeverShareYourSecret';
var server = require('./basic_server'); // test server which in turn loads our module
test("Attempt to access restricted content (without auth token)", function(t) {
var options = {
method: "POST",
url: "/privado"
};
// server.inject lets us simulate an http request
server.inject(options, function(response) {
t.equal(response.statusCode, 401, "No Token should fail");
t.end();
});
});
test("Attempt to access restricted content (with an INVALID Token)", function(t) {
var options = {
method: "POST",
url: "/privado",
headers: { authorization: "Bearer fails.validation" }
};
// server.inject lets us simulate an http request
server.inject(options, function(response) {
t.equal(response.statusCode, 401, "INVALID Token should fail");
t.end();
});
});
test("Malformed JWT", function(t) {
// use the token as the 'authorization' header in requests
// var token = jwt.sign({ "id": 1 ,"name":"Old Greg" }, 'incorrectSecret');
// console.log(token);
var options = {
method: "POST",
url: "/privado",
headers: { authorization: "Bearer my.invalid.token" }
};
// server.inject lets us simulate an http request
server.inject(options, function(response) {
// console.log(response.result);
// console.log(' '); // blank line
t.equal(response.statusCode, 401, "INVALID Token should fail");
// t.equal(JSON.parse(response.result).msg, 'Invalid Token', "INVALID Token should fail");
t.end();
});
});
test("Try using a token with missing characters in body", function(t) {
// use the token as the 'authorization' header in requests
var token = JWT.sign({ id: 123, "name": "Charlie" }, secret);
// delete some characters in body
var tokenData = token.split('.');
var header = tokenData[0],
body = tokenData[1],
signature = tokenData[2];
token = header + '.' + body.substring(0, body.length - 1) + '.' + signature;
/*console.log(" - - - - - - token - - - - -");
console.log(token);*/
var options = {
method: "POST",
url: "/privado",
headers: { authorization: "Bearer " + token }
};
// server.inject lets us simulate an http request
server.inject(options, function(response) {
t.equal(response.statusCode, 401, "INVALID Token should fail");
t.end();
});
});
test("Try using an incorrect secret to sign the JWT", function(t) {
// use the token as the 'authorization' header in requests
var token = JWT.sign({ id: 123, "name": "Charlie" }, 'incorrectSecret');
// console.log(" - - - - - - token - - - - -")
// console.log(token);
var options = {
method: "POST",
url: "/privado",
headers: { authorization: "Bearer " + token }
};
// server.inject lets us simulate an http request
server.inject(options, function(response) {
t.equal(response.statusCode, 401, "Token signed with incorrect key fails");
t.end();
});
});
// see: https://github.com/dwyl/hapi-auth-jwt2/issues/166
// test.only("Try using an expired token", function(t) {
// // use the token as the 'authorization' header in requests
// var token = JWT.sign({ id: 123, "name": "Charlie" }, secret, { expiresInSeconds: 1 });
// console.log(" - - - - - - token - - - - -")
// console.log(token);
// var options = {
// method: "POST",
// url: "/privado",
// headers: { authorization: "Bearer " + token }
// };
// // server.inject lets us simulate an http request
// setTimeout(function () {
// server.inject(options, function(response) {
// t.equal(response.statusCode, 401, "Expired token should be invalid");
// t.equal(response.result.message, 'Token expired', 'Message should be "Token expired"');
// t.end();
// });
// }, 1000);
// });
test("Token is well formed but is allowed=false so should be denied", function(t) {
// use the token as the 'authorization' header in requests
// var token = jwt.sign({ "id": 1 ,"name":"Old Greg" }, 'incorrectSecret');
var token = JWT.sign({ id: 321, "name": "Old Gregg" }, secret);
var options = {
method: "POST",
url: "/privado",
headers: { authorization: "Bearer " + token }
};
// server.inject lets us simulate an http request
server.inject(options, function(response) {
t.equal(response.statusCode, 401, "Denied");
t.end();
});
});
test("Access restricted content (with VALID Token)", function(t) {
// use the token as the 'authorization' header in requests
var token = JWT.sign({ id: 123, "name": "Charlie" }, secret);
var options = {
method: "POST",
url: "/privado",
headers: { authorization: "Bearer " + token }
};
// server.inject lets us simulate an http request
server.inject(options, function(response) {
// console.log(" - - - - RESPONSE: ")
// console.log(response.result);
t.equal(response.statusCode, 200, "VALID Token should succeed!");
t.end();
});
});
test("Access restricted content (with Well-formed but invalid Token)", function(t) {
// use the token as the 'authorization' header in requests
var token = JWT.sign({ id: 123, "name": "Charlie" }, 'badsecret');
var options = {
method: "POST",
url: "/privado",
headers: { authorization: "Bearer " + token }
};
// server.inject lets us simulate an http request
server.inject(options, function(response) {
// console.log(" - - - - RESPONSE: ")
// console.log(response.result);
t.equal(response.statusCode, 401, "InVALID Token should Error!");
t.end();
});
});
// see: https://github.com/ideaq/hapi-auth-jwt2/issues/28
test("Request with undefined auth header should 401", function(t) {
var options = {
method: "POST",
url: "/privado",
headers: { authorization: "Bearer " }
};
// server.inject lets us simulate an http request
server.inject(options, function(response) {
// console.log(" - - - - RESPONSE: ")
// console.log(response.result);
t.equal(response.statusCode, 401, "InVALID Token fails (as expected)!");
t.end();
});
});
test("Auth mode 'required' should require authentication header", function(t) {
var options = {
method: "POST",
url: "/required"
};
// server.inject lets us simulate an http request
server.inject(options, function(response) {
t.equal(response.statusCode, 401, "No token header should fail in auth 'required' mode");
t.end();
});
});
test("Auth mode 'required' should fail with invalid token", function(t) {
// use the token as the 'authorization' header in requests
var token = JWT.sign({ id: 123, "name": "Charlie" }, 'badsecret');
var options = {
method: "POST",
url: "/required",
headers: { authorization: "Bearer " + token }
};
// server.inject lets us simulate an http request
server.inject(options, function(response) {
// console.log(" - - - - RESPONSE: ")
// console.log(response.result);
t.equal(response.statusCode, 401, "Invalid token should error!");
t.end();
});
});
test("Auth mode 'required' should should pass with valid token", function(t) {
// use the token as the 'authorization' header in requests
var token = JWT.sign({ id: 123, "name": "Charlie" }, secret);
var options = {
method: "POST",
url: "/required",
headers: { authorization: "Bearer " + token }
};
// server.inject lets us simulate an http request
server.inject(options, function(response) {
// console.log(" - - - - RESPONSE: ")
// console.log(response.result);
t.equal(response.statusCode, 200, "Valid token should succeed!");
t.end();
});
});
test("Auth mode 'optional' should pass when no auth header specified", function(t) {
var options = {
method: "POST",
url: "/optional"
};
server.inject(options, function(response) {
// console.log(" - - - - RESPONSE: ")
// console.log(response.result);
t.equal(response.statusCode, 200, "No auth header should pass in optional mode!");
t.end();
});
});
test("Auth mode 'optional' should fail with invalid token", function(t) {
// use the token as the 'authorization' header in requests
var token = JWT.sign({ id: 123, "name": "Charlie" }, 'badsecret');
var options = {
method: "POST",
url: "/optional",
headers: { authorization: "Bearer " + token }
};
// server.inject lets us simulate an http request
server.inject(options, function(response) {
// console.log(" - - - - RESPONSE: ")
// console.log(response.result);
t.equal(response.statusCode, 401, "Invalid token should error!");
t.end();
});
});
test("Auth mode 'optional' should pass with valid token", function(t) {
// use the token as the 'authorization' header in requests
// var token = JWT.sign({ id: 123, "name": "Charlie" }, secret);
var token = JWT.sign({ id: 123, "name": "Charlie" }, secret);
var options = {
method: "POST",
url: "/optional",
headers: { authorization: "Bearer " + token }
};
// server.inject lets us simulate an http request
server.inject(options, function(response) {
// console.log(" - - - - RESPONSE: ")
// console.log(response.result);
t.equal(response.statusCode, 200, "Valid token should succeed!");
t.end();
});
});
test("Auth mode 'try' should pass when no auth header specified", function(t) {
var options = {
method: "POST",
url: "/try"
};
server.inject(options, function(response) {
// console.log(" - - - - RESPONSE: ")
// console.log(response.result);
t.equal(response.statusCode, 200, "No auth header should pass in 'try' mode!");
t.end();
});
});
test("Auth mode 'try' should pass with invalid token", function(t) {
// use the token as the 'authorization' header in requests
var token = JWT.sign({ id: 123, "name": "Charlie" }, 'badsecret');
var options = {
method: "POST",
url: "/try",
headers: { authorization: "Bearer " + token }
};
// server.inject lets us simulate an http request
server.inject(options, function(response) {
// console.log(" - - - - RESPONSE: ")
// console.log(response.result);
t.equal(response.statusCode, 200, "Invalid token should pass in 'try' mode");
t.end();
});
});
test("Auth mode 'try' should pass with valid token", function(t) {
// use the token as the 'authorization' header in requests
var token = JWT.sign({ id: 123, "name": "Charlie" }, secret);
var options = {
method: "POST",
url: "/try",
headers: { authorization: "Bearer " + token }
};
// server.inject lets us simulate an http request
server.inject(options, function(response) {
// console.log(" - - - - RESPONSE: ")
// console.log(response);
t.equal(response.statusCode, 200, "Valid token should succeed!");
t.end();
});
});
test("Scheme should set token in request.auth.token", function(t) {
// use the token as the 'authorization' header in requests
var token = JWT.sign({ id: 123, "name": "Charlie" }, secret);
var options = {
method: "GET",
url: "/token",
headers: { authorization: "Bearer " + token }
};
// server.inject lets us simulate an http request
server.inject(options, function(response) {
// console.log(" - - - - RESPONSE: ")
// console.log(response.result);
t.equal(response.result, token, 'Token is accesible from handler');
t.end();
});
});
test.onFinish(function () {
server.stop(function(){});
})
var test = require('tape');
var Hapi = require('hapi');
var JWT = require('jsonwebtoken');
var secret = 'NeverShareYourSecret';
var keyDict = { 5678: secret };
var server = new Hapi.Server();
server.connection();
test('Full token payload (header + payload + signature) is available to key lookup function using completeToken option', function (t) {
server.register(require('../'), function (err) {
t.ifError(err, 'No error registering hapi-auth-jwt2 plugin');
server.auth.strategy('jwt', 'jwt', {
key: function (decoded, callback) {
var signatureKey = keyDict[decoded.header.x5t]; // Look dynamically for key based on JWT header field
return callback(null, signatureKey);
},
complete: true,
validateFunc: function (decoded, request, callback) {
return callback(null, true);
},
verifyOptions: {algorithms: ['HS256']}
});
server.route({
method: 'POST',
path: '/',
handler: function (request, reply) { return reply('Ok'); },
config: { auth: 'jwt' }
});
var options = {
method: 'POST',
url: '/',
headers: {Authorization: JWT.sign({ id: 1234 }, secret, { header: { x5t: 5678 } })} // set custom JWT header field "x5t"
};
server.inject(options, function (response) {
t.equal(response.statusCode, 200, 'Server returned 200 status');
t.end();
});
});
});
test.onFinish(function () {
server.stop(function(){});
})
var test = require('tape');
var JWT = require('jsonwebtoken');
var secret = 'NeverShareYourSecret';
var server = require('./basic_server.js');
var cookie_options = '; Max-Age=31536000;'; //' Expires=Mon, 18 Jul 2016 05:29:45 GMT; Secure; HttpOnly';
// var cookie_options = {
// ttl: 365 * 30 * 7 * 24 * 60 * 60 * 1000, // in the distant future ...
// encoding: 'none', // we already used JWT to encode
// isSecure: true, // warm & fuzzy feelings
// isHttpOnly: true, // prevent client alteration
// clearInvalid: false, // remove invalid cookies
// strictHeader: true // don't allow violations of RFC 6265
// }
test("Attempt to access restricted content using inVALID Cookie Token", function(t) {
var token = JWT.sign({ id: 123, "name": "Charlie" }, 'badsecret');
var options = {
method: "POST",
url: "/privado",
headers: { cookie: "token=" + token }
};
console.log(options);
server.inject(options, function(response) {
t.equal(response.statusCode, 401, "Invalid token should error!");
t.end();
});
});
test("Attempt to access restricted content with VALID Token but malformed Cookie", function(t) {
var token = JWT.sign({ id: 123, "name": "Charlie" }, secret);
var options = {
method: "POST",
url: "/privado",
headers: { cookie: token }
};
// server.inject lets us simulate an http request
server.inject(options, function(response) {
t.equal(response.statusCode, 400, "Valid Token but inVALID COOKIE should fial!");
t.end();
});
});
test("Access restricted content with VALID Token Cookie", function(t) {
var token = JWT.sign({ id: 123, "name": "Charlie" }, secret);
var options = {
method: "POST",
url: "/privado",
headers: { cookie: "token=" + token }
};
// server.inject lets us simulate an http request
server.inject(options, function(response) {
t.equal(response.statusCode, 200, "VALID COOKIE Token should succeed!");
t.end();
});
});
test("Access restricted content with VALID Token Cookie (With Options!)", function(t) {
var token = JWT.sign({ id: 123, "name": "Charlie" }, secret);
var options = {
method: "POST",
url: "/privado",
headers: { cookie: "token=" + token + cookie_options }
};
// console.log(' - - - - - - - - - - - - - - - OPTIONS:')
// console.log(options);
// server.inject lets us simulate an http request
server.inject(options, function(response) {
// console.log(' - - - - - - - - - - - - - - - response:')
// console.log(response);
t.equal(response.statusCode, 200, "VALID COOKIE Token (With Options!) should succeed!");
t.end();
});
});
/** Regressions Tests for https://github.com/dwyl/hapi-auth-jwt2/issues/65 **/
// supply valid Token Auth Header but invalid Cookie
// should succeed because Auth Header is first
test("Authorization Header should take precedence over any cookie", function(t) {
var token = JWT.sign({ id: 123, "name": "Charlie" }, secret);
var options = {
method: "POST",
url: "/privado",
headers: {
authorization: "Bearer " + token,
cookie: "token=malformed.token" + cookie_options
}
};
server.inject(options, function(response) {
// console.log(' - - - - - - - - - - - - - - - response:')
// console.log(response);
t.equal(response.statusCode, 200, "Ignores cookie when Auth Header is set");
t.end();
});
});
// valid google analytics cookie but invalid auth header token
// see: https://github.com/dwyl/hapi-auth-jwt2/issues/65#issuecomment-124791842
test("Valid Google Analytics cookie should be ignored", function(t) {
var GA = "gwcm=%7B%22expires%22%3Anull%2C%22clabel%22%3A%22SbNVCILRtFcQwcrE6gM%22%2C%22backoff%22%3A1437241242%7D; _ga=GA1.2.1363734468.1432273334";
var token = JWT.sign({ id: 123, "name": "Charlie" }, secret);
var options = {
method: "POST",
url: "/privado",
headers: {
authorization: "Bearer " + token,
cookie: GA
}
};
server.inject(options, function(response) {
t.equal(response.statusCode, 200, "Ignores Google Analytics Cookie");
t.end();
});
});
test("Valid Google Analytics cookie should be ignored (BAD Header Token)", function(t) {
var GA = "gwcm=%7B%22expires%22%3Anull%2C%22clabel%22%3A%22SbNVCILRtFcQwcrE6gM%22%2C%22backoff%22%3A1437241242%7D; _ga=GA1.2.1363734468.1432273334";
var token = JWT.sign({ id: 123, "name": "Charlie" }, 'invalid');
var options = {
method: "POST",
url: "/privado",
headers: {
authorization: "Bearer " + token,
cookie: GA
}
};
server.inject(options, function(response) {
t.equal(response.statusCode, 401, "Ignores GA but Invalid Auth Header still rejected");
t.end();
});
});
// Supply a VALID Token in Cookie A-N-D valid GA in Cookie!!
test("Valid Google Analytics cookie should be ignored (BAD Header Token)", function(t) {
var GA = "gwcm=%7B%22expires%22%3Anull%2C%22clabel%22%3A%22SbNVCILRtFcQwcrE6gM%22%2C%22backoff%22%3A1437241242%7D; _ga=GA1.2.1363734468.1432273334";
var token = JWT.sign({ id: 123, "name": "Charlie" }, secret);
var options = {
method: "POST",
url: "/privado",
headers: {
cookie: "token=" + token + '; ' + GA
}
};
server.inject(options, function(response) {
t.equal(response.statusCode, 200, "Valid Cookie Token Succeeds (Ignores GA)");
t.end();
});
});
test("Attempt to access restricted content with cookieKey=false", function(t) {
var token = JWT.sign({ id: 123, "name": "Charlie" }, secret);
var options = {
method: "POST",
url: "/privadonocookie",
headers: { cookie: "token=" + token }
};
// server.inject lets us simulate an http request
server.inject(options, function(response) {
t.equal(response.statusCode, 401, "Disabled cookie auth shouldn't accept valid token!");
t.end();
});
});
test("Attempt to access restricted content with cookieKey=''", function(t) {
var token = JWT.sign({ id: 123, "name": "Charlie" }, secret);
var options = {
method: "POST",
url: "/privadonocookie2",
headers: { cookie: "=" + token }
};
// server.inject lets us simulate an http request
server.inject(options, function(response) {
t.equal(response.statusCode, 400, "Disabled cookie auth shouldn't accept valid token!");
t.end();
});
});
var test = require('tape');
var JWT = require('jsonwebtoken');
var secret = 'NeverShareYourSecret';
var server = require('./custom_parameters_server.js');
var cookie_options = '; Max-Age=31536000;'; //' Expires=Mon, 18 Jul 2016 05:29:45 GMT; Secure; HttpOnly';
// Those tests are the same as cookie-test and url-token-test but with custom parameters in cookie or URL
test("Attempt to access restricted content using inVALID Cookie Token - custom parameters", function(t) {
var token = JWT.sign({ id: 123, "name": "Charlie" }, 'badsecret');
var options = {
method: "POST",
url: "/privado",
headers: { cookie: "customCookieKey=" + token }
};
console.log(options);
server.inject(options, function(response) {
t.equal(response.statusCode, 401, "Invalid token should error!");
t.end();
});
});
test("Attempt to access restricted content with VALID Token but malformed Cookie - custom parameters", function(t) {
var token = JWT.sign({ id: 123, "name": "Charlie" }, secret);
var options = {
method: "POST",
url: "/privado",
headers: { cookie: token }
};
// server.inject lets us simulate an http request
server.inject(options, function(response) {
t.equal(response.statusCode, 400, "Valid Token but inVALID COOKIE should fial!");
t.end();
});
});
test("Access restricted content with VALID Token Cookie - custom parameters", function(t) {
var token = JWT.sign({ id: 123, "name": "Charlie" }, secret);
var options = {
method: "POST",
url: "/privado",
headers: { cookie: "customCookieKey=" + token }
};
// server.inject lets us simulate an http request
server.inject(options, function(response) {
t.equal(response.statusCode, 200, "VALID COOKIE Token should succeed!");
t.end();
});
});
test("Access restricted content with VALID Token Cookie (With Options!) - custom parameters", function(t) {
var token = JWT.sign({ id: 123, "name": "Charlie" }, secret);
var options = {
method: "POST",
url: "/privado",
headers: { cookie: "customCookieKey=" + token + cookie_options }
};
// console.log(' - - - - - - - - - - - - - - - OPTIONS:')
// console.log(options);
// server.inject lets us simulate an http request
server.inject(options, function(response) {
// console.log(' - - - - - - - - - - - - - - - response:')
// console.log(response);
t.equal(response.statusCode, 200, "VALID COOKIE Token (With Options!) should succeed!");
t.end();
});
});
/** Regressions Tests for https://github.com/dwyl/hapi-auth-jwt2/issues/65 **/
// supply valid Token Auth Header but invalid Cookie
// should succeed because Auth Header is first
test("Authorization Header should take precedence over any cookie - custom parameters", function(t) {
var token = JWT.sign({ id: 123, "name": "Charlie" }, secret);
var options = {
method: "POST",
url: "/privado",
headers: {
authorization: "MyAuthScheme " + token,
cookie: "customCookieKey=malformed.token" + cookie_options
}
};
server.inject(options, function(response) {
// console.log(' - - - - - - - - - - - - - - - response:')
// console.log(response);
t.equal(response.statusCode, 200, "Ignores cookie when Auth Header is set");
t.end();
});
});
// valid google analytics cookie but invalid auth header token
// see: https://github.com/dwyl/hapi-auth-jwt2/issues/65#issuecomment-124791842
test("Valid Google Analytics cookie should be ignored - custom parameters", function(t) {
var GA = "gwcm=%7B%22expires%22%3Anull%2C%22clabel%22%3A%22SbNVCILRtFcQwcrE6gM%22%2C%22backoff%22%3A1437241242%7D; _ga=GA1.2.1363734468.1432273334";
var token = JWT.sign({ id: 123, "name": "Charlie" }, secret);
var options = {
method: "POST",
url: "/privado",
headers: {
authorization: "MyAuthScheme " + token,
cookie: GA
}
};
server.inject(options, function(response) {
t.equal(response.statusCode, 200, "Ignores Google Analytics Cookie");
t.end();
});
});
test("Valid Google Analytics cookie should be ignored (BAD Header Token) - custom parameters", function(t) {
var GA = "gwcm=%7B%22expires%22%3Anull%2C%22clabel%22%3A%22SbNVCILRtFcQwcrE6gM%22%2C%22backoff%22%3A1437241242%7D; _ga=GA1.2.1363734468.1432273334";
var token = JWT.sign({ id: 123, "name": "Charlie" }, 'invalid');
var options = {
method: "POST",
url: "/privado",
headers: {
authorization: "MyAuthScheme " + token,
cookie: GA
}
};
server.inject(options, function(response) {
t.equal(response.statusCode, 401, "Ignores GA but Invalid Auth Header still rejected");
t.end();
});
});
// Supply a VALID Token in Cookie A-N-D valid GA in Cookie!!
test("Valid Google Analytics cookie should be ignored (BAD Header Token) - custom parameters", function(t) {
var GA = "gwcm=%7B%22expires%22%3Anull%2C%22clabel%22%3A%22SbNVCILRtFcQwcrE6gM%22%2C%22backoff%22%3A1437241242%7D; _ga=GA1.2.1363734468.1432273334";
var token = JWT.sign({ id: 123, "name": "Charlie" }, secret);
var options = {
method: "POST",
url: "/privado",
headers: {
cookie: "customCookieKey=" + token + '; ' + GA
}
};
server.inject(options, function(response) {
t.equal(response.statusCode, 200, "Valid Cookie Token Succeeds (Ignores GA)");
t.end();
});
});
test("Attempt to access restricted content (with an INVALID URL Token) - custom parameters", function(t) {
var token = "?customUrlKey=my.invalid.token";
var options = {
method: "POST",
url: "/privado" + token
};
// server.inject lets us simulate an http request
server.inject(options, function(response) {
t.equal(response.statusCode, 401, "INVALID Token should fail");
t.end();
});
});
test("Try using an incorrect secret to sign the JWT - custom parameters", function(t) {
// use the token as the 'authorization' header in requests
var token = JWT.sign({ id: 123, "name": "Charlie" }, 'incorrectSecret');
token = "?customUrlKey=" + token;
// console.log(" - - - - - - token - - - - -")
// console.log(token);
var options = {
method: "POST",
url: "/privado" + token
};
// server.inject lets us simulate an http request
server.inject(options, function(response) {
t.equal(response.statusCode, 401, "URL Token signed with incorrect key fails");
t.end();
});
});
test("URL Token is well formed but is allowed=false so should be denied - custom parameters", function(t) {
// use the token as the 'authorization' header in requests
// var token = jwt.sign({ "id": 1 ,"name":"Old Greg" }, 'incorrectSecret');
var token = JWT.sign({ id: 321, "name": "Old Gregg" }, secret);
token = "?customUrlKey=" + token;
var options = {
method: "POST",
url: "/privado" + token
};
// server.inject lets us simulate an http request
server.inject(options, function(response) {
t.equal(response.statusCode, 401, "User is Denied");
t.end();
});
});
test("Access restricted content (with VALID Token) - custom parameters", function(t) {
// use the token as the 'authorization' header in requests
var token = JWT.sign({ id: 123, "name": "Charlie" }, secret);
token = "?customUrlKey=" + token;
var options = {
method: "POST",
url: "/privado" + token
};
// server.inject lets us simulate an http request
server.inject(options, function(response) {
t.equal(response.statusCode, 200, "VALID Token should succeed!");
t.end();
});
});
test("Attempt to access restricted content using inVALID header tokenType - custom parameters", function(t) {
var token = JWT.sign({ id: 123, "name": "Charlie" }, 'badsecret');
var options = {
method: "POST",
url: "/privado",
headers: { Authorization: "InvalidAuthScheme " + token }
};
server.inject(options, function(response) {
t.equal(response.statusCode, 401, "Invalid token should error!");
t.end();
});
});
test("Access restricted content (with VALID Token and header tokenType) - custom parameters", function(t) {
var token = JWT.sign({ id: 123, "name": "Charlie" }, secret);
var options = {
method: "POST",
url: "/privado",
headers: { Authorization: "MyAuthScheme " + token }
};
server.inject(options, function(response) {
t.equal(response.statusCode, 200, "VALID Token should succeed!");
t.end();
});
});
var test = require('tape');
var Hapi = require('hapi');
var JWT = require('jsonwebtoken');
var secret = 'NeverShareYourSecret';
var keyDict = { 5678: secret };
test('When using a custom header key full token payload (header + payload + signature) is available to key lookup function using completeToken option', function (t) {
var server = new Hapi.Server();
server.connection();
server.register(require('../'), function (err) {
t.ifError(err, 'No error registering hapi-auth-jwt2 plugin');
server.auth.strategy('jwt', 'jwt', {
key: function (decoded, callback) {
var signatureKey = keyDict[decoded.header.x5t]; // Look dynamically for key based on JWT header field
return callback(null, signatureKey);
},
complete: true,
validateFunc: function (decoded, request, callback) {
return callback(null, true);
},
verifyOptions: {algorithms: ['HS256']},
headerKey: 'auths'
});
server.route({
method: 'POST',
path: '/',
handler: function (request, reply) { return reply('Ok'); },
config: { auth: 'jwt' }
});
var options = {
method: 'POST',
url: '/',
headers: {auths: JWT.sign({ id: 1234 }, secret, { header: { x5t: 5678 } })} // set custom JWT header field "x5t"
};
server.inject(options, function (response) {
t.equal(response.statusCode, 200, 'Server returned 200 status');
t.end();
});
});
});
var test = require('tape');
var JWT = require('jsonwebtoken');
var server = require('./dynamic_key_server'); // test server which in turn loads our module
test("Access restricted content with a valid token and tenant", function(t) {
// use the token as the 'authorization' header in requests
var token = JWT.sign({ id: 123, "name": "Charlie", "tenant": "dunderMifflin" }, 'michaelscott');
var options = {
method: "POST",
url: "/privado",
headers: { authorization: "Bearer " + token }
};
// server.inject lets us simulate an http request
server.inject(options, function(response) {
console.log(" - - - - RESPONSE: ");
console.log(response.result);
t.equal(response.statusCode, 200, "VALID Token should succeed!");
t.equal(response.result.data.additional, 'something extra here if needed', 'extraInfo should be passed through');
t.end();
});
});
test("Access restricted content with an invalid token and tenant", function(t) {
// use the token as the 'authorization' header in requests
var token = JWT.sign({ id: 123, "name": "Charlie", "tenant": "dunderMifflin" }, 'dwightschrute');
var options = {
method: "POST",
url: "/privado",
headers: { authorization: "Bearer " + token }
};
// server.inject lets us simulate an http request
server.inject(options, function(response) {
console.log(" - - - - RESPONSE: ");
console.log(response.result);
t.equal(response.statusCode, 401, "INVALID Token should fail!");
t.end();
});
});
test("Access restricted content with a valid token and tenant but user is not allowed", function(t) {
// use the token as the 'authorization' header in requests
var token = JWT.sign({ id: 321, "name": "Old Gregg", "tenant": "wernhamHogg" }, 'davidbrent');
var options = {
method: "POST",
url: "/privado",
headers: { authorization: "Bearer " + token }
};
// server.inject lets us simulate an http request
server.inject(options, function(response) {
console.log(" - - - - RESPONSE: ");
console.log(response.result);
t.equal(response.statusCode, 401, "Not allowed user should fail!");
t.end();
});
});
test("Access restricted content without tenant specified in token", function(t) {
// use the token as the 'authorization' header in requests
var token = JWT.sign({ id: 123, "name": "Charlie" }, 'michaelscott');
var options = {
method: "POST",
url: "/privado",
headers: { authorization: "Bearer " + token }
};
// server.inject lets us simulate an http request
server.inject(options, function(response) {
console.log(" - - - - RESPONSE: ");
console.log(response.result);
t.equal(response.statusCode, 400, "No tenant specified should fail!");
t.end();
});
});
test("Access restricted content with non-existent tenant specified", function(t) {
// use the token as the 'authorization' header in requests
var token = JWT.sign({ id: 123, "name": "Charlie", "tenant": "princeFamilyPaper" }, 'michaelscott');
var options = {
method: "POST",
url: "/privado",
headers: { authorization: "Bearer " + token }
};
// server.inject lets us simulate an http request
server.inject(options, function(response) {
console.log(" - - - - RESPONSE: ");
console.log(response.result);
t.equal(response.statusCode, 401, "No tentant found should fail!");
t.end();
});
});
var test = require('tape');
var JWT = require('jsonwebtoken');
// var secret = 'NeverShareYourSecret';
var server = require('./error_func_server'); // test server which in turn loads our module
test("Access a route that has no auth strategy", function(t) {
var options = {
method: "GET",
url: "/"
};
// server.inject lets us simulate an http request
server.inject(options, function(response) {
t.equal(response.statusCode, 200, "GET / still works without token.");
t.end();
});
});
test("customVerify simulate error condition", function(t) {
var payload = { id: 123, "name": "Charlie", error: true }
var token = JWT.sign(payload, 'SecretDoesNOTGetVerified');
var options = {
method: "GET",
url: "/required",
headers: { authorization: "Bearer " + token }
};
// server.inject lets us simulate an http request
server.inject(options, function(response) {
t.equal(response.statusCode, 500, "customVerify force error");
t.equal(response.result.message, "An internal server error occurred", "GET /required with forced error that has not been customised");
t.end();
});
});
test("customVerify simulate error condition but is safely not customised", function(t) {
var payload = { id: 123, "name": "Charlie", custom_error: 'ignore'}
var token = JWT.sign(payload, 'SecretDoesNOTGetVerified');
var options = {
method: "GET",
url: "/required",
headers: { authorization: "Bearer " + token }
};
// server.inject lets us simulate an http request
server.inject(options, function(response) {
t.equal(response.statusCode, 500, "customVerify force error");
t.equal(response.result.message, "An internal server error occurred", "GET /required with forced error that has not been customised");
t.end();
});
});
test("customVerify with fail condition", function(t) {
var payload = { id: 123, "name": "Charlie", some_property: false }
var token = JWT.sign(payload, 'SecretDoesNOTGetVerified');
var options = {
method: "GET",
url: "/required",
headers: { authorization: "Bearer " + token }
};
// server.inject lets us simulate an http request
server.inject(options, function(response) {
t.equal(response.statusCode, 401, "GET /required with customVerify rejected");
t.equal(response.result.message, "Invalid credentials mate", "GET /required with customVerify rejected and customised error message");
t.end();
});
});
test("Custom Verification in 'try' mode ", function(t) {
var payload = { id: 123, "name": "Charlie", some_property: true }
var token = JWT.sign(payload, 'SecretDoesNOTGetVerified');
var options = {
method: "GET",
url: "/try",
headers: { authorization: "Bearer " + token }
};
// server.inject lets us simulate an http request
server.inject(options, function(response) {
t.equal(response.result.id, payload.id, 'Decoded JWT returned by handler');
t.equal(response.statusCode, 200, "GET /try bypasses verification");
t.end();
});
});
test("Custom Verification in 'optional' mode ", function(t) {
var payload = { id: 234, "name": "Oscar", some_property: true }
var token = JWT.sign(payload, 'SecretDoesNOTGetVerified');
var options = {
method: "GET",
url: "/optional",
headers: { authorization: "Bearer " + token }
};
// server.inject lets us simulate an http request
server.inject(options, function(response) {
t.equal(response.result.id, payload.id, 'Decoded JWT returned by handler');
t.equal(response.statusCode, 200, "GET /optional bypasses verification");
t.end();
});
});
test("Custom Verification in 'required' mode ", function(t) {
var payload = { id: 345, "name": "Romeo", some_property: true }
var token = JWT.sign(payload, 'AnyStringWillDo');
var options = {
method: "GET",
url: "/required",
headers: { authorization: "Bearer " + token }
};
// server.inject lets us simulate an http request
server.inject(options, function(response) {
// console.log(response.result);
var credentials = JSON.parse(JSON.stringify(response.result));
t.equal(credentials.id, payload.id, 'Decoded JWT is available in handler');
t.equal(response.statusCode, 200, "GET /required bypasses verification");
t.end();
});
});
var test = require('tape');
var JWT = require('jsonwebtoken');
var secret = 'NeverShareYourSecret';
var server = require('./scheme-response-server'); // test server which in turn loads our module
test("Attempt to access restricted content (without auth token)", function(t) {
var options = {
method: "POST",
url: "/privado"
};
server.inject(options, function(response) {
t.equal(response.statusCode, 401, "No Token should fail");
t.equal(response.headers.authorization, undefined, 'Invalid requests should not be calling the response function');
t.end();
});
});
test("Attempt to access restricted content (with an INVALID Token)", function(t) {
var options = {
method: "POST",
url: "/privado",
headers: { authorization: "Bearer fails.validation" }
};
server.inject(options, function(response) {
t.equal(response.statusCode, 401, "INVALID Token should fail");
t.equal(response.headers.authorization, undefined, 'Invalid requests should not be calling the response function');
t.end();
});
});
test("Access restricted content (with VALID Token)", function(t) {
// use the token as the 'authorization' header in requests
var token = JWT.sign({ id: 123, "name": "Charlie" }, secret);
var options = {
method: "POST",
url: "/privado",
headers: { authorization: "Bearer " + token }
};
server.inject(options, function(response) {
t.equal(response.statusCode, 200, "VALID Token should succeed!");
t.equal(response.headers.authorization, 'from scheme response function', 'Valid request should finish by calling response function');
t.end();
});
});
test("Auth mode 'required' should require authentication header", function(t) {
var options = {
method: "POST",
url: "/required"
};
server.inject(options, function(response) {
t.equal(response.statusCode, 401, "No token header should fail in auth 'required' mode");
t.equal(response.headers.authorization, undefined, 'Invalid requests should not be calling the response function');
t.end();
});
});
test("Auth mode 'required' should should pass with valid token", function(t) {
// use the token as the 'authorization' header in requests
var token = JWT.sign({ id: 123, "name": "Charlie" }, secret);
var options = {
method: "POST",
url: "/required",
headers: { authorization: "Bearer " + token }
};
server.inject(options, function(response) {
t.equal(response.statusCode, 200, "Valid token should succeed!");
t.equal(response.headers.authorization, 'from scheme response function', 'Valid request should finish by calling response function');
t.end();
});
});
test("Scheme should set token in request.auth.token", function(t) {
// use the token as the 'authorization' header in requests
var token = JWT.sign({ id: 123, "name": "Charlie" }, secret);
var options = {
method: "GET",
url: "/token",
headers: { authorization: "Bearer " + token }
};
server.inject(options, function(response) {
t.equal(response.result, token, 'Token is accesible from handler');
t.equal(response.headers.authorization, 'from scheme response function', 'Valid request should finish by calling response function');
t.end();
});
});
test("Testing an error thrown from the scheme\'s response function", function(t) {
// use the token as the 'authorization' header in requests
var token = JWT.sign({ id: 123, "name": "Charlie" }, secret);
var options = {
method: "GET",
url: "/token",
headers: {
authorization: "Bearer " + token,
error: 'true'
}
};
// server.inject lets us simulate an http request
server.inject(options, function(response) {
t.equal(response.statusCode, 500, 'A server error happens in the scheme\'s response function');
t.end();
});
});
var test = require('tape');
var JWT = require('jsonwebtoken');
var secret = 'NeverShareYourSecret'; // set by ENV Variable
var server = require('./scopes_server'); // test server which in turn loads our module
test("Access restricted content using scopes (with VALID Token and VALID scope)", function(t) {
// use the token as the 'authorization' header in requests
var token = JWT.sign({ id: 123, "name": "Charlie" }, secret);
var options = {
method: "POST",
url: "/privado-with-scope",
headers: { authorization: "Bearer " + token }
};
// server.inject lets us simulate an http request
server.inject(options, function(response) {
console.log(" - - - - RESPONSE: ");
console.log(response.result);
t.equal(response.statusCode, 200, "VALID Token should succeed!");
t.end();
});
});
test("Access restricted content using scopes (with VALID Token and INVALID scope)", function(t) {
// use the token as the 'authorization' header in requests
var token = JWT.sign({ id: 321, "name": "Old Gregg" }, secret);
var options = {
method: "POST",
url: "/privado-with-scope",
headers: { authorization: "Bearer " + token }
};
// server.inject lets us simulate an http request
server.inject(options, function(response) {
console.log(" - - - - RESPONSE: ");
console.log(response.result);
t.equal(response.statusCode, 401, "Denied");
t.end();
});
});
var test = require('tape');
var JWT = require('jsonwebtoken');
var secret = 'NeverShareYourSecret';
var server = require('./basic_server.js');
test("Attempt to access restricted content (without auth token)", function(t) {
var options = {
method: "POST",
url: "/privado"
};
// server.inject lets us simulate an http request
server.inject(options, function(response) {
t.equal(response.statusCode, 401, "No Token supplied > fails (as expected)");
t.end();
});
});
test("Attempt to access restricted content (with an INVALID URL Token)", function(t) {
var token = "?token=my.invalid.token";
var options = {
method: "POST",
url: "/privado" + token
};
// server.inject lets us simulate an http request
server.inject(options, function(response) {
t.equal(response.statusCode, 401, "INVALID Token should fail");
t.end();
});
});
test("Try using an incorrect secret to sign the JWT", function(t) {
// use the token as the 'authorization' header in requests
var token = JWT.sign({ id: 123, "name": "Charlie" }, 'incorrectSecret');
token = "?token=" + token;
// console.log(" - - - - - - token - - - - -")
// console.log(token);
var options = {
method: "POST",
url: "/privado" + token
};
// server.inject lets us simulate an http request
server.inject(options, function(response) {
t.equal(response.statusCode, 401, "URL Token signed with incorrect key fails");
t.end();
});
});
test("URL Token is well formed but is allowed=false so should be denied", function(t) {
// use the token as the 'authorization' header in requests
// var token = jwt.sign({ "id": 1 ,"name":"Old Greg" }, 'incorrectSecret');
var token = JWT.sign({ id: 321, "name": "Old Gregg" }, secret);
token = "?token=" + token;
var options = {
method: "POST",
url: "/privado" + token
};
// server.inject lets us simulate an http request
server.inject(options, function(response) {
t.equal(response.statusCode, 401, "User is Denied");
t.end();
});
});
test("Access restricted content (with VALID Token)", function(t) {
// use the token as the 'authorization' header in requests
var token = JWT.sign({ id: 123, "name": "Charlie" }, secret);
token = "?token=" + token;
var options = {
method: "POST",
url: "/privado" + token
};
// server.inject lets us simulate an http request
server.inject(options, function(response) {
t.equal(response.statusCode, 200, "VALID Token should succeed!");
t.end();
});
});
test("Using route with urlKey=false should be denied", function(t) {
// use the token as the 'authorization' header in requests
var token = JWT.sign({ id: 123, "name": "Charlie" }, secret);
token = "?token=" + token;
var options = {
method: "POST",
url: "/privadonourl" + token
};
// server.inject lets us simulate an http request
server.inject(options, function(response) {
t.equal(response.statusCode, 401, "No urlKey configured so URL-Tokens should be denied");
t.end();
});
});
test("Using route with urlKey='' should be denied", function(t) {
// use the token as the 'authorization' header in requests
var token = JWT.sign({ id: 123, "name": "Charlie" }, secret);
token = "?=" + token;
var options = {
method: "POST",
url: "/privadonourl2" + token
};
// server.inject lets us simulate an http request
server.inject(options, function(response) {
t.equal(response.statusCode, 401, "No urlKey configured so URL-Tokens should be denied");
t.end();
});
});
var test = require('tape');
var Hapi = require('hapi');
var JWT = require('jsonwebtoken');
var secret = 'NeverShareYourSecret';
test('Should respond with 500 series error when validateFunc errs', function (t) {
var server = new Hapi.Server();
server.connection();
server.register(require('../'), function (err) {
t.ifError(err, 'No error registering hapi-auth-jwt2 plugin');
server.auth.strategy('jwt', 'jwt', {
key: secret,
validateFunc: function (decoded, request, callback) {
return callback(new Error('ASPLODE'));
},
verifyOptions: {algorithms: ['HS256']}
});
server.route({
method: 'POST',
path: '/privado',
handler: function (req, reply) { return reply('PRIVADO'); },
config: { auth: 'jwt' }
});
var options = {
method: 'POST',
url: '/privado',
headers: {Authorization: JWT.sign({id: 138, name: 'Test'}, secret)}
};
server.inject(options, function (response) {
t.equal(response.statusCode, 500, 'Server returned 500 for validateFunc error');
t.end();
});
});
});
var test = require('tape');
var JWT = require('jsonwebtoken');
// var secret = 'NeverShareYourSecret';
var server = require('./verify_func_server'); // test server which in turn loads our module
test("Access a route that has no auth strategy", function(t) {
var options = {
method: "GET",
url: "/"
};
// server.inject lets us simulate an http request
server.inject(options, function(response) {
t.equal(response.statusCode, 200, "GET / still works without token.");
t.end();
});
});
test("customVerify simulate error condition", function(t) {
var payload = { id: 123, "name": "Charlie", error: true }
var token = JWT.sign(payload, 'SecretDoesNOTGetVerified');
var options = {
method: "GET",
url: "/required",
headers: { authorization: "Bearer " + token }
};
// server.inject lets us simulate an http request
server.inject(options, function(response) {
t.equal(response.statusCode, 500, "customVerify force error");
t.end();
});
});
test("customVerify with fail condition", function(t) {
var payload = { id: 123, "name": "Charlie", some_property: false }
var token = JWT.sign(payload, 'SecretDoesNOTGetVerified');
var options = {
method: "GET",
url: "/required",
headers: { authorization: "Bearer " + token }
};
// server.inject lets us simulate an http request
server.inject(options, function(response) {
t.equal(response.statusCode, 401, "GET /required with customVerify rejected");
t.end();
});
});
test("Custom Verification in 'try' mode ", function(t) {
var payload = { id: 123, "name": "Charlie", some_property: true }
var token = JWT.sign(payload, 'SecretDoesNOTGetVerified');
var options = {
method: "GET",
url: "/try",
headers: { authorization: "Bearer " + token }
};
// server.inject lets us simulate an http request
server.inject(options, function(response) {
t.equal(response.result.id, payload.id, 'Decoded JWT returned by handler');
t.equal(response.statusCode, 200, "GET /try bypasses verification");
t.end();
});
});
test("Custom Verification in 'optional' mode ", function(t) {
var payload = { id: 234, "name": "Oscar", some_property: true }
var token = JWT.sign(payload, 'SecretDoesNOTGetVerified');
var options = {
method: "GET",
url: "/optional",
headers: { authorization: "Bearer " + token }
};
// server.inject lets us simulate an http request
server.inject(options, function(response) {
t.equal(response.result.id, payload.id, 'Decoded JWT returned by handler');
t.equal(response.statusCode, 200, "GET /optional bypasses verification");
t.end();
});
});
test("Custom Verification in 'required' mode ", function(t) {
var payload = { id: 345, "name": "Romeo", some_property: true }
var token = JWT.sign(payload, 'AnyStringWillDo');
var options = {
method: "GET",
url: "/required",
headers: { authorization: "Bearer " + token }
};
// server.inject lets us simulate an http request
server.inject(options, function(response) {
// console.log(response.result);
var credentials = JSON.parse(JSON.stringify(response.result));
t.equal(credentials.id, payload.id, 'Decoded JWT is available in handler');
t.equal(response.statusCode, 200, "GET /required bypasses verification");
t.end();
});
});