hapi-auth-jwt2
Advanced tools
Comparing version 5.8.0 to 6.0.0
@@ -8,13 +8,12 @@ var Cookie = require('cookie'); // highly popular decoupled cookie parser | ||
module.exports = function (request, options) { | ||
// The key holding token value in url or cookie defaults to token | ||
var urlKey = typeof options.urlKey === 'string' ? options.urlKey : 'token'; | ||
var cookieKey = typeof options.cookieKey === 'string' ? options.cookieKey : 'token'; | ||
var headerKey = typeof options.headerKey === 'string' ? options.headerKey : 'authorization'; | ||
var urlKey = options.urlKey === false || typeof options.urlKey === 'string' ? options.urlKey : 'token'; | ||
var cookieKey = options.cookieKey === false || typeof options.cookieKey === 'string' ? options.cookieKey : 'token'; | ||
var headerKey = options.headerKey === false || typeof options.headerKey === 'string' ? options.headerKey : 'authorization'; | ||
var auth; | ||
if(request.query[urlKey]) { // tokens via url: https://github.com/dwyl/hapi-auth-jwt2/issues/19 | ||
if(urlKey && request.query[urlKey]) { // tokens via url: https://github.com/dwyl/hapi-auth-jwt2/issues/19 | ||
auth = request.query[urlKey]; | ||
} // JWT tokens in cookie: https://github.com/dwyl/hapi-auth-jwt2/issues/55 | ||
else if (request.headers[headerKey]) { | ||
else if (headerKey && request.headers[headerKey]) { | ||
if (typeof options.tokenType === 'string') { | ||
@@ -27,3 +26,3 @@ var token = request.headers[headerKey].match(new RegExp(options.tokenType + '\\s+([^$]+)', 'i')); | ||
} | ||
else if (request.headers.cookie) { | ||
else if (cookieKey && request.headers.cookie) { | ||
auth = Cookie.parse(request.headers.cookie)[cookieKey]; | ||
@@ -30,0 +29,0 @@ } |
@@ -61,6 +61,3 @@ var Boom = require('boom'); // error handling https://github.com/hapijs/boom | ||
JWT.verify(token, key, verifyOptions, function (err, decoded) { | ||
if (err && err.name === 'TokenExpiredError') { | ||
return reply(Boom.unauthorized('Token expired', 'Token'), null, { credentials: null }); | ||
} | ||
else if (err) { | ||
if (err) { | ||
return reply(Boom.unauthorized('Invalid token', 'Token'), null, { credentials: null }); | ||
@@ -67,0 +64,0 @@ } |
{ | ||
"name": "hapi-auth-jwt2", | ||
"version": "5.8.0", | ||
"version": "6.0.0", | ||
"description": "Hapi.js Authentication Plugin/Scheme using JSON Web Tokens (JWT)", | ||
@@ -40,3 +40,3 @@ "main": "lib/index.js", | ||
"cookie": "^0.2.3", | ||
"jsonwebtoken": "^5.7.0" | ||
"jsonwebtoken": "^6.2.0" | ||
}, | ||
@@ -46,4 +46,4 @@ "devDependencies": { | ||
"hapi": "^13.3.0", | ||
"istanbul": "^0.4.2", | ||
"jshint": "^2.9.1", | ||
"istanbul": "^0.4.3", | ||
"jshint": "^2.9.2", | ||
"pre-commit": "^1.1.2", | ||
@@ -50,0 +50,0 @@ "tap-spec": "^4.1.1", |
@@ -9,3 +9,3 @@ # Hapi Auth using JSON Web Tokens (JWT) | ||
[](https://travis-ci.org/dwyl/hapi-auth-jwt2) | ||
[](https://codecov.io/github/dwyl/hapi-auth-jwt2?branch=master) | ||
[](https://codecov.io/github/dwyl/hapi-auth-jwt2?branch=master) | ||
[](https://codeclimate.com/github/dwyl/hapi-auth-jwt2) | ||
@@ -25,6 +25,6 @@ [](http://hapijs.com) | ||
If you are totally new to JWTs, we wrote an introductory post explaining | ||
If you are totally new to JWTs, we wrote an introductory post explaining | ||
the concepts & benefits: https://github.com/dwyl/learn-json-web-tokens | ||
If you (or anyone on your team) are unfamiliar with **Hapi.js** we have a | ||
If you (or anyone on your team) are unfamiliar with **Hapi.js** we have a | ||
quick guide for that too: https://github.com/dwyl/learn-hapi | ||
@@ -177,3 +177,3 @@ | ||
- `decoded` - (***required***) is the ***decoded*** and ***verified*** JWT received from the client in **request.headers.authorization** | ||
- `request` - (***required***) is the original ***request*** received from the client | ||
- `request` - (***required***) is the original ***request*** received from the client | ||
- `callback` - (***required***) a callback function with the signature `function(err, isValid, credentials)` where: | ||
@@ -195,6 +195,6 @@ - `err` - an internal error. | ||
- `reply(err, response)`- is called if an error occurred | ||
- `urlKey` - (***optional*** *defaults to* `'token'`) - if you prefer to pass your token via url, simply add a `token` url parameter to your request or use a custom parameter by setting `urlKey` | ||
- `cookieKey` - (***optional*** *defaults to* `'token'`) if you prefer to set your own cookie key or your project has a cookie called `'token'` for another purpose, you can set a custom key for your cookie by setting `options.cookieKey='yourkeyhere'`. | ||
- `headerKey` - (***optional*** *defaults to* `'authorization'`) - if you want to set a custom key for your header token use the `headerKey` option. | ||
- `tokenType` - (***optional*** *defaults to noe*) allow custom token type, e.g. `Authorization: <tokenType> 12345678`. | ||
- `urlKey` - (***optional*** *defaults to* `'token'`) - if you prefer to pass your token via url, simply add a `token` url parameter to your request or use a custom parameter by setting `urlKey`. To disable the url parameter set urlKey to `false` or ''. | ||
- `cookieKey` - (***optional*** *defaults to* `'token'`) - if you prefer to set your own cookie key or your project has a cookie called `'token'` for another purpose, you can set a custom key for your cookie by setting `options.cookieKey='yourkeyhere'`. To disable cookies set cookieKey to `false` or ''. | ||
- `headerKey` - (***optional*** *defaults to* `'authorization'`) - if you want to set a custom key for your header token use the `headerKey` option. To disable header token set headerKey to `false` or ''. | ||
- `tokenType` - (***optional*** *defaults to none*) - allow custom token type, e.g. `Authorization: <tokenType> 12345678`. | ||
- `complete` - (***optional*** *defaults to* `false`) - set to `true` to receive the complete token (`decoded.header`, `decoded.payload` and `decoded.signature`) as `decoded` argument to key lookup and `verifyFunc` callbacks (*not `validateFunc`*) | ||
@@ -295,3 +295,3 @@ | ||
> What if I want to *disable* the ability to pass JWTs in via the URL? | ||
(*asked by* @bitcloud in [issue #146](https://github.com/dwyl/hapi-auth-jwt2/pull/146)) | ||
(*asked by* @bitcloud in [issue #146](https://github.com/dwyl/hapi-auth-jwt2/pull/146)) | ||
> simply set your `urlKey` to something *impossible* to guess see: | ||
@@ -304,3 +304,3 @@ [*example*](https://github.com/dwyl/hapi-auth-jwt2/pull/146#issuecomment-205481751) | ||
There are _several_ options for generating secret keys. | ||
There are _several_ options for generating secret keys. | ||
The _easist_ way is to run node's crypto hash in your terminal: | ||
@@ -310,3 +310,3 @@ ```js | ||
``` | ||
and copy the resulting base64 key and use it as your JWT secret. | ||
and copy the resulting base64 key and use it as your JWT secret. | ||
If you are *curious* how strong that key is watch: https://youtu.be/koJQQWHI-ZA | ||
@@ -326,3 +326,3 @@ | ||
and it's only useful if you want to use to make | ||
request to other servers using the user's token. | ||
request to other servers using the user's token. | ||
@@ -335,3 +335,3 @@ The *decoded* version of the token, accessible via `request.auth.credentials` | ||
requested the ability to send/receive tokens as cookies: | ||
[dwyl/hapi-auth-jwt2/issues/**55**](https://github.com/dwyl/hapi-auth-jwt2/issues/55) | ||
[dwyl/hapi-auth-jwt2/issues/**55**](https://github.com/dwyl/hapi-auth-jwt2/issues/55) | ||
So we added the ability to *optionally* send/store your tokens in cookies | ||
@@ -383,18 +383,18 @@ to simplify building your *web app*. | ||
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) | ||
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) | ||
**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] ? | ||
**A**: Yes, you need to *manually* install the **jsonwebtoken** | ||
node module from NPM with `npm install jsonwebtoken --save` if you want to ***sign*** JWTs in your app. | ||
node module from NPM with `npm install jsonwebtoken --save` if you want to ***sign*** JWTs in your app. | ||
Even though **hapi-auth-jwt2** includes it | ||
as a **dependency** your app does not know where to find it in the **node_modules** tree for your project. | ||
as a **dependency** your app does not know where to find it in the **node_modules** tree for your project. | ||
Unless you include it via ***relative path*** e.g: | ||
`var JWT = require('./node_modules/hapi-auth-jwt2/node_modules/jsonwebtoken');` | ||
`var JWT = require('./node_modules/hapi-auth-jwt2/node_modules/jsonwebtoken');` | ||
we *recommend* including it in your **package.json** ***explicitly*** as a **dependency** for your project. | ||
2. Can we supply a ***Custom Verification*** function instead of using the **JWT.verify** method? | ||
2. 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) | ||
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. | ||
**Q**: Does this module support custom verification function or disabling verification? | ||
**A**: Yes, it *does now*! (*see: "Advanced Usage" below*) the inclusion of a `verifyFunc` | ||
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. | ||
**Q**: Does this module support custom verification function or disabling verification? | ||
**A**: Yes, it *does now*! (*see: "Advanced Usage" below*) the inclusion of a `verifyFunc` | ||
gives you *complete control* over the verification of the incoming JWT. | ||
@@ -406,3 +406,3 @@ | ||
While *most* people using `hapi-auth-jwt2` will opt for the *simpler* use case | ||
(*using a* ***Validation Function*** *`validateFunc` - see: Basic Usage example above - | ||
(*using a* ***Validation Function*** *`validateFunc` - see: Basic Usage example above - | ||
which validates the JWT payload after it has been verified...*) | ||
@@ -421,3 +421,3 @@ others may need more control over the `verify` step. | ||
- `decoded` - (***required***) is the ***decoded*** and ***verified*** JWT received from the client in **request.headers.authorization** | ||
- `request` - (***required***) is the original ***request*** received from the client | ||
- `request` - (***required***) is the original ***request*** received from the client | ||
- `callback` - (***required***) a callback function with the signature `function(err, isValid, credentials)` where: | ||
@@ -429,3 +429,3 @@ - `err` - an internal error. | ||
The advantage of this approach is that it allows people to write a | ||
custom verification function or to bypass the `JWT.verify` *completely*. | ||
custom verification function or to bypass the `JWT.verify` *completely*. | ||
For more detail, see: use-case discussion in https://github.com/dwyl/hapi-auth-jwt2/issues/120 | ||
@@ -435,3 +435,3 @@ | ||
> ***Note***: *nobody has requested the ability to use* ***both*** *a* | ||
`validateFunc` ***and*** `verifyFunc`. | ||
`validateFunc` ***and*** `verifyFunc`. | ||
This should not be *necessary* | ||
@@ -453,3 +453,3 @@ because with a `verifyFunc` you can incorporate your own custom-logic. | ||
> *If you have a question, or need help getting started* ***please post an issue/question on | ||
> *If you have a question, or need help getting started* ***please post an issue/question on | ||
GitHub***: https://github.com/dwyl/hapi-auth-jwt2/issues *or* | ||
@@ -500,3 +500,3 @@ [](https://gitter.im/dwyl/chat/?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) | ||
If you have ***any questions*** on this please post an issue/question on GitHub: | ||
https://github.com/dwyl/hapi-auth-jwt2/issues | ||
https://github.com/dwyl/hapi-auth-jwt2/issues | ||
(*we are here to help get you started on your journey to **hapi**ness!*) | ||
@@ -510,3 +510,3 @@ | ||
If you spot an area for improvement, please raise an issue: https://github.com/dwyl/hapi-auth-jwt2/issues | ||
If you spot an area for improvement, please raise an issue: https://github.com/dwyl/hapi-auth-jwt2/issues | ||
*Someone* in the dwyl team is *always* online so we will usually answer within a few hours. | ||
@@ -532,3 +532,3 @@ | ||
While making [***Time***](https://github.com/dwyl/time) we want to ensure | ||
our app (and API) is as ***simple*** as *possible* to use. | ||
our app (and API) is as ***simple*** as *possible* to use. | ||
This lead us to using JSON Web Tokens for ***Stateless*** Authentication. | ||
@@ -541,3 +541,3 @@ | ||
but they were invariably ***too complicated***, poorly documented and | ||
had *useless* (non-real-world) "examples"! | ||
had *useless* (non-real-world) "examples"! | ||
@@ -554,3 +554,3 @@ Also, none of the *existing* modules exposed the **request** object | ||
The name we wanted was taken. | ||
The name we wanted was taken. | ||
Think of our module as the "***new, simplified and actively maintained version***" | ||
@@ -557,0 +557,0 @@ |
@@ -44,2 +44,30 @@ var Hapi = require('hapi'); | ||
server.auth.strategy('jwt-nourl', 'jwt', { | ||
key: secret, | ||
validateFunc: validate, | ||
verifyOptions: { algorithms: [ 'HS256' ] }, // only allow HS256 algorithm | ||
urlKey: false | ||
}); | ||
server.auth.strategy('jwt-nocookie', 'jwt', { | ||
key: secret, | ||
validateFunc: validate, | ||
verifyOptions: { algorithms: [ 'HS256' ] }, // only allow HS256 algorithm | ||
cookieKey: false | ||
}); | ||
server.auth.strategy('jwt-nourl2', 'jwt', { | ||
key: secret, | ||
validateFunc: validate, | ||
verifyOptions: { algorithms: [ 'HS256' ] }, // only allow HS256 algorithm | ||
urlKey: '' | ||
}); | ||
server.auth.strategy('jwt-nocookie2', 'jwt', { | ||
key: secret, | ||
validateFunc: validate, | ||
verifyOptions: { algorithms: [ 'HS256' ] }, // only allow HS256 algorithm | ||
cookieKey: '' | ||
}); | ||
server.route([ | ||
@@ -49,2 +77,6 @@ { method: 'GET', path: '/', handler: home, config: { auth: false } }, | ||
{ method: 'POST', path: '/privado', handler: privado, config: { auth: 'jwt' } }, | ||
{ method: 'POST', path: '/privadonourl', handler: privado, config: { auth: 'jwt-nourl' } }, | ||
{ method: 'POST', path: '/privadonocookie', handler: privado, config: { auth: 'jwt-nocookie' } }, | ||
{ method: 'POST', path: '/privadonourl2', handler: privado, config: { auth: 'jwt-nourl2' } }, | ||
{ method: 'POST', path: '/privadonocookie2', handler: privado, config: { auth: 'jwt-nocookie2' } }, | ||
{ method: 'POST', path: '/required', handler: privado, config: { auth: { mode: 'required', strategy: 'jwt' } } }, | ||
@@ -51,0 +83,0 @@ { method: 'POST', path: '/optional', handler: privado, config: { auth: { mode: 'optional', strategy: 'jwt' } } }, |
@@ -91,21 +91,22 @@ var test = require('tape'); | ||
test("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); | ||
}); | ||
// 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); | ||
// }); | ||
@@ -336,1 +337,5 @@ test("Token is well formed but is allowed=false so should be denied", function(t) { | ||
}); | ||
test.onFinish(function () { | ||
server.stop(function(){}); | ||
}) |
@@ -8,7 +8,8 @@ var test = require('tape'); | ||
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) { | ||
var server = new Hapi.Server(); | ||
server.connection(); | ||
server.register(require('../'), function (err) { | ||
@@ -39,3 +40,3 @@ t.ifError(err, 'No error registering hapi-auth-jwt2 plugin'); | ||
url: '/', | ||
headers: {Authorization: JWT.sign({ id: 1234 }, secret, { headers: { x5t: 5678 } })} // set custom JWT header field "x5t" | ||
headers: {Authorization: JWT.sign({ id: 1234 }, secret, { header: { x5t: 5678 } })} // set custom JWT header field "x5t" | ||
}; | ||
@@ -49,1 +50,6 @@ | ||
}); | ||
test.onFinish(function () { | ||
server.stop(function(){}); | ||
}) |
@@ -150,1 +150,31 @@ var test = require('tape'); | ||
}); | ||
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(); | ||
}); | ||
}); | ||
@@ -40,3 +40,3 @@ var test = require('tape'); | ||
url: '/', | ||
headers: {auths: JWT.sign({ id: 1234 }, secret, { headers: { x5t: 5678 } })} // set custom JWT header field "x5t" | ||
headers: {auths: JWT.sign({ id: 1234 }, secret, { header: { x5t: 5678 } })} // set custom JWT header field "x5t" | ||
}; | ||
@@ -43,0 +43,0 @@ |
@@ -79,1 +79,31 @@ var test = require('tape'); | ||
}); | ||
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(); | ||
}); | ||
}); |
Sorry, the diff of this file is not supported yet
98969
1867
+ Addedhoek@2.16.3(transitive)
+ Addedisemail@1.2.0(transitive)
+ Addedjoi@6.10.1(transitive)
+ Addedjsonwebtoken@6.2.0(transitive)
+ Addedmoment@2.30.1(transitive)
+ Addedtopo@1.1.0(transitive)
- Removedjsonwebtoken@5.7.0(transitive)
Updatedjsonwebtoken@^6.2.0