hapi.js, JWT and CORS
In the last post we setup a React based authentication workflow for a sample application. In this short post we will look at a hapi.js backend that can handle authentication using JWT and since the React frontend runs on a different port (via Webpack) we will also setup CORS.
Setting up CORS and JWT with Hapi is actually quite easy. For CORS all we need to do is provide the right options to hapi’s server.connection and JWT setup is available as a hapi plugin. Let’s look at a working example -
server.js -
'use strict';
var Hapi = require('hapi'), _ = require('lodash'), config = require('./server/config/app'), routes = require('./server/config/routes'), User = require('./server/models/user');
// Create a server with a host and portvar server = new Hapi.Server();
//Server config ***** CORS setup here *****server.connection(_.pick(config, ['host', 'port', 'routes']));
//Logging setupvar goodOptions = { reporters: [{ reporter: require('good-console'), events: { log: '*', request: '*', response: '*' } }]};
//Authserver.register([require('hapi-auth-jwt2'), { register: require('good'), options: goodOptions }], function(err) { if(err){ console.log(err); }
//***** JWT setup here ***** server.auth.strategy( 'jwt', 'jwt', { key: config.secretKey, validateFunc: User.validate, //The validation function verifyOptions: { algorithms: [ 'HS256' ] } });
server.auth.default('jwt');});
// Add the routeserver.route(routes.config);
// Start the serverserver.start(function() { console.log('Server running at:', server.info.uri);});
module.exports = server;
app.js (where we have the CORS configuration enabled for development) -
var config = { development: { host: 'localhost', port: 3000, routes: {cors: true}, secretKey: 'so74565467rs3cr3t132189328213213n123123dasd12341239i0dsf' }, test: { host: 'localhost', port: 3001, secretKey: 'foobar' }}
var env = process.env['NODE_ENV'] || 'development';module.exports = config[env];
An example routes.js -
var GreetingController = require('../controllers/greeting_controller'), UsersController = require('../controllers/users_controller'), SessionsController = require('../controllers/sessions_controller');
var routes = { config: [ {method: 'GET', path: '/api/greeting', config: {handler: GreetingController.show}}, {method: 'POST', path: '/api/users', config: {auth: false, handler: UsersController.create}}, {method: 'GET', path: '/api/session', config: {handler: SessionsController.show}}, {method: 'POST', path: '/api/session', config: {auth: false, handler: SessionsController.create}}, {method: 'DELETE', path: '/api/session', config: {handler: SessionsController.delete}} ]};
module.exports = routes;
The User.validation function used in the JWT setup could look something like -
validate: function (decoded, request, callback) { const promise = new User({id: decoded.id}).fetch(); promise.then(function(data) { if(data === null){ return callback(null, false); } else { return callback(null, true); } }); promise.catch(function(e) { return callback(null, false); });}
The Github project has the complete source code.