When working with Express.js you will at some point require some kind of authentication. In my case, since I have moved away from server side rendering and use Angular for the front-end and Express.js or Hapi for my REST API, I choose to use JWT tokens for my authentication needs.
I will not cover JWT tokens as it would make this post much longer and also because there are so many awesome posts about it out there, like this blog post by Flavio Copes.
So what can you use for Express when you want your front end to authenticate requests via a JWT token? Well the de facto standard is Passport.JS.
Passport.js as the official documentation states is:
“Passport is authentication middleware for Node.js. Extremely flexible and modular…"
Modular is the keyword here, as the middleware contains hundreds of different strategies which can be used, depending on your needs.
Because of my requirements I will focus on Passport’s Bearer strategy, and how you can integrate it with your Express backend.
Bearer auth, or token authentication, is an HTTP authentication scheme which comprises security tokens called bearer tokens. The token is usually a cryptic string, and is generated in response to a successful login on the part of a user.
A client must include this token in the Authorization header when making requests to any protected resource on the server. As I have stated I use JWT tokens but of course you can use any type of token you choose.
Lets start by installing Passport.js
npm install passport
At this point we can include the Bearer strategy in our code, the middleware configuration code looks like this:
passport.use(new BearerStrategy(
function(token, done){
// Validation logic here
return done(null, user, { scope: 'read' });
}
));
When calling done
you can optionally pass the scopes, like you see above, for later use in your backend.
So let’s add a sample authentication logic to our config code. I will of course also use a JWT token module to help me out.
I personally prefer jwt-simple
which can be found here
npm install jwt-simple
Lets use the JWT module with the bearer strategy config.
var jwt = require('jwt-simple');
var User = require('./models/user.js'); // Sample user model
passport.use(new BearerStrategy(
function(token, done){
try {
//we attempt to validate the token the client sent with the request
var decoded = jwt.decode(token, MY_JWT_SECRET);
// Check that the token has not expired
// if expired return done(null, false);
// Find the user represents by the subject claims
User.findOne({ email: decoded.sub }, function (err, user) {
if (err) { return done(err); }
if (!user) {
return done(null, false); //no such user
}
else {
return done(null, user); //allows the call chain to continue to the intented route
}
});
}
catch(err){
return done(null, false); //returns a 401 to the caller
}
}
));
That is all. The code above will intercept all requests that require authentication and will first of all validate the token. If the token is valid you can then look up the user in the database and call done
with the actual user. Or if for some reason you need to return an error or the user does not exist in the database you will need to call done
passing an error.
To lock your route and access an authenticated user you will need to simply specify that the route requires authentication and then you can gain access to the user by calling req.user
.
app.get('/secure', passport.authenticate('bearer', { session: false }), function(req, res, next){
// Get the authenticated user.
var user = req.user;
// Route implementation here...
});
To disable session support and ensure we do not set any cookies you can use { session: false }
in the call to passport.
Ok so how can you store your token client side and still maintain security?
The token can be easily stored in session storage
or local storage
because they are sand boxed and not accessible by other sites or scripts.
A proper authentication server will usually return both an access token
and a refresh token
when a user authenticates.
Access token will normally be short lived, no more than 24hrs. While a refresh token
will be long lived and will be used to gain a new access token
when the token has expired. This ensures that a user does not need to authenticate often, but at the same time it allows the backend to black list and deny access to a user.
Disclaimer: The code above is only meant for documentation purposes and is NOT production ready. Kindly refer to Passport.js and Jwt-Simple’s documentation.