Skip to content

Commit

Permalink
Merge pull request #8 from joseluisdiaz/hapi-17
Browse files Browse the repository at this point in the history
Supports HAPI 17 API
  • Loading branch information
dafortune committed Feb 14, 2018
2 parents a1cdfa7 + c6627af commit 2743288
Show file tree
Hide file tree
Showing 5 changed files with 485 additions and 626 deletions.
73 changes: 36 additions & 37 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,12 @@ See the example folder for an executable example.

```javascript

var Hapi = require('hapi'),
jwt = require('jsonwebtoken'),
server = new Hapi.Server();
const Hapi = require('hapi');
const jwt = require('jsonwebtoken');
const server = new Hapi.Server({ port: 8080 });

server.connection({ port: 8080 });


var accounts = {
const accounts = {
123: {
id: 123,
user: 'john',
Expand All @@ -41,57 +39,58 @@ var accounts = {
};


var privateKey = 'BbZJjyoXAdr8BUZuiKKARWimKfrSmQ6fv8kZ7OFfc';
const privateKey = 'BbZJjyoXAdr8BUZuiKKARWimKfrSmQ6fv8kZ7OFfc';

// Use this token to build your request with the 'Authorization' header.
// Use this token to build your request with the 'Authorization' header.
// Ex:
// Authorization: Bearer <token>
var token = jwt.sign({ accountId: 123 }, privateKey);
const token = jwt.sign({ accountId: 123 }, privateKey);


var validate = function (decodedToken, extraInfo, callback) {
const validate = async function (decodedToken, extraInfo) {

var error,
credentials = accounts[decodedToken.accountId] || {};
var credentials = accounts[decodedToken.accountId] || {};

if (!credentials) {
return callback(error, false, credentials);
return { isValid: false };
}

return callback(error, true, credentials)
return {
isValid: true,
credentials
}
};


server.register(require('hapi-auth-jwt'), function (error) {
await server.register(require('hapi-auth-jwt'));

server.auth.strategy('token', 'jwt', {
key: privateKey,
validateFunc: validate
});
server.auth.strategy('token', 'jwt', {
key: privateKey,
validateFunc: validate
});

server.route({
method: 'GET',
path: '/',
config: {
auth: 'token'
}
});
server.route({
method: 'GET',
path: '/',
config: {
auth: 'token'
}
});

// With scope requirements
server.route({
method: 'GET',
path: '/withScope',
config: {
auth: {
strategy: 'token',
scope: ['a']
}
server.route({
method: 'GET',
path: '/withScope',
config: {
auth: {
strategy: 'token',
scope: ['a']
}
});
}
});


server.start();
await server.start();

```

Expand All @@ -106,4 +105,4 @@ server.auth.strategy('token', 'jwt', {
algorithms: ['RS256'],
subject: 'myRequiredSubject'
});
```
```
101 changes: 46 additions & 55 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,115 +2,106 @@

var Boom = require('boom');
var Hoek = require('hoek');
var jwt = require('jsonwebtoken');
var jwt = require('jsonwebtoken');
var Joi = require('joi');

var optionsSchema = Joi.object().keys({
key: Joi.alternatives().try(Joi.binary(),Joi.func()).required(),
key: Joi.alternatives().try(Joi.binary(), Joi.func()).required(),
validateFunc: Joi.func(),
algorithms: Joi.array().items(Joi.string()),
audience: Joi.alternatives().try(Joi.string(),Joi.array().items(Joi.string())),
issuer: Joi.alternatives().try(Joi.string(),Joi.array().items(Joi.string())),
audience: Joi.alternatives().try(Joi.string(), Joi.array().items(Joi.string())),
issuer: Joi.alternatives().try(Joi.string(), Joi.array().items(Joi.string())),
subject: Joi.string()
}).label('jwt auth strategy options');

// Declare internals
var internals = {};


exports.register = function (server, options, next) {

function register(server, options) {
server.auth.scheme('jwt', internals.implementation);
next();
};

exports.register.attributes = {
pkg: require('../package.json')
};

function isFunction(functionToCheck) {
return Object.prototype.toString.call(functionToCheck) === '[object Function]';
}

internals.implementation = function (server, options) {

var validationResult = Joi.validate(options, optionsSchema);

if (validationResult.error){
if (validationResult.error) {
throw new Error(validationResult.error.message);
}

var settings = Hoek.clone(options);

var scheme = {
authenticate: function (request, reply) {
authenticate: async function (request, h) {

var req = request.raw.req;
var authorization = req.headers.authorization;
if (!authorization) {
return reply(Boom.unauthorized(null, 'Bearer'));
throw Boom.unauthorized(null, 'Bearer');
}

var parts = authorization.split(/\s+/);

if (parts.length !== 2) {
return reply(Boom.badRequest('Bad HTTP authentication header format', 'Bearer'));
throw Boom.badRequest('Bad HTTP authentication header format', 'Bearer');
}

if (parts[0].toLowerCase() !== 'bearer') {
return reply(Boom.unauthorized(null, 'Bearer'));
throw Boom.unauthorized(null, 'Bearer');
}

if(parts[1].split('.').length !== 3) {
return reply(Boom.badRequest('Bad HTTP authentication header format', 'Bearer'));
if (parts[1].split('.').length !== 3) {
throw Boom.badRequest('Bad HTTP authentication header format', 'Bearer');
}

var token = parts[1];

var getKey = isFunction(settings.key) ?
var getKey = typeof settings.key === 'function' ?
settings.key :
function(req, token, callback) { callback(null, settings.key); };
function (req, token) { return { key: settings.key }; };

getKey(request, token, function(err, key, extraInfo){
if (err) { return reply(Boom.wrap(err)); }
// handle err
jwt.verify(token, key, settings, function(err, decoded) {

if(err) {
return reply(Boom.unauthorized( 'JSON Web Token validation failed: ' + err.message, 'Bearer'));
}

if (!settings.validateFunc) {
return reply.continue({ credentials: decoded });
}
let keyResult;

settings.validateFunc(decoded, extraInfo, function (err, isValid, credentials) {
try {
keyResult = await getKey(request, token);
} catch (err) {
throw Boom.boomify(err, { override: false });
}

credentials = credentials || null;
const { key, extraInfo } = keyResult;

if (err) {
return reply(err, null, { credentials: credentials, log: { tags: ['auth', 'jwt'], data: err } });
}
let decoded;
try {
decoded = jwt.verify(token, key, settings);
} catch (err) {
throw Boom.unauthorized('JSON Web Token validation failed: ' + err.message, 'Bearer');
}

if (!isValid) {
return reply(Boom.unauthorized('Invalid token', 'Bearer'), null, { credentials: credentials });
}
if (!settings.validateFunc) {
return h.authenticated({ credentials: decoded });
}

if (!credentials || typeof credentials !== 'object') {
const validateResult = await settings.validateFunc(decoded, extraInfo);

return reply(Boom.badImplementation('Bad credentials object received for jwt auth validation'), null, { log: { tags: 'credentials' } });
}
const { isValid, credentials } = validateResult;

// Authenticated
if (!isValid) {
throw Boom.unauthorized('Invalid token', 'Bearer');
}

return reply.continue({ credentials: credentials });
});
if (!credentials || typeof credentials !== 'object') {
throw Boom.badImplementation('Bad credentials object received for jwt auth validation');
}

});
});
// Authenticated
return h.authenticated({ credentials });
}
};

return scheme;

return scheme;
};

module.exports = {
pkg: require('../package.json'),
register,
}
21 changes: 12 additions & 9 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "hapi-auth-jwt",
"description": "JSON Web Token (JWT) authentication plugin",
"version": "4.1.0",
"version": "5.0.0",
"author": "Ryan Fitzgerald <[email protected]>",
"repository": "git://github.com/ryanfitz/hapi-auth-jwt",
"main": "index",
Expand All @@ -12,23 +12,26 @@
"JWT"
],
"engines": {
"node": ">=4.x.x"
"node": ">=8.9.x"
},
"dependencies": {
"boom": "2.x.x",
"hoek": "2.x.x",
"joi": "^10.0.1",
"jsonwebtoken": "^5.4.1"
"boom": "^7.1.1",
"hoek": "^5.0.3",
"joi": "^13.1.2",
"jsonwebtoken": "^8.1.1"
},
"devDependencies": {
"code": "1.x.x",
"hapi": "11.x.x",
"lab": "5.x.x",
"code": "5.x.x",
"hapi": ">=17.x.x",
"lab": "15.x.x",
"grunt": "0.4.x",
"grunt-contrib-jshint": "0.11.x",
"grunt-contrib-watch": "0.6.x",
"grunt-bump": "0.1.x"
},
"peerDependencies": {
"hapi": ">=17.x.x"
},
"scripts": {
"test": "make test-cov"
},
Expand Down
Loading

0 comments on commit 2743288

Please sign in to comment.