REST — Token based authentication (jwt)

Aditya Mhamunkar
4 min readFeb 8, 2018

You can see the same mails with exact same data and time-stamps on your Gmail account from a variety of devices. It is obvious that all your devices are pulling this email data from a single source provided by Google. This device and platform independence is achieved by separating the clients (Laptop browser, Smartphone app, Tablet app, etc.) from the server. And one of the most popular way to achieve this is using a REST architecture.

REST stands for REpresentational State Transfer. REST is a web standards based architecture and uses HTTP Protocol for data communication, making it easier for systems to communicate with each other.

Separation of client and server

In REST architecture, the client and the server can be implemented independently without knowing each other. This independence of implementation gives freedom to change the client code without affecting the server and vice versa. Both the sides (client and server) knows what format of messages to send to each other and hence the independence is achieved.

By using a REST interface, different clients hit the same REST endpoints, perform the same actions, and receive the same responses.

Statelessness

Systems that follow the REST paradigm are stateless, meaning that the server does not need to know anything about what state the client is in and vice versa. For example, a RESTful server does not maintain user session. It is completely unaware whether a user is logged in or not.

Access tokens

When a client sends the login information (email and password), the RESTful server sends back an encrypted access token with an expiration time to the client if the email and password are valid. Now, when the same user needs some resources, it sends a request to the server attaching the same access token. The server verifies the token and if valid, sends back the requested data. Thus, server does not need to keep track or store the logged in users and can support millions of users simultaneously with high performance.

This is the beauty of a REST architecture.

An access token is nothing but a long string used as a key to the server by a valid user. Formally, the Access Token is a credential that can be used by a client to access an API. There is a special type of encrypted access token called JWT — JSON Web Token. The JWT encrypts user information along with a payload which turns to be an efficient way to verify the user’s validity.

Implementing token based authentication

We will be using Node.js with Express and MongoDB with Mongoose in the reference code. Also, we will be using JWT — jsonwebtoken package (https://www.npmjs.com/package/jsonwebtoken).

The following function is executed when the user/client posts a login form with email and password. The function finds the email from the list of users in the database and matches the password. If its a match, it generates a JWT with a payload consisting of user’s role (admin or general user) and user id. Also, it assigns a expiry time (one hour in this example).

const express = require('express');
const router = express.Router();
const password_hash = require('password-hash');
const jwt = require('jsonwebtoken');
const app = express();router.post('/api/user/validate', (req, res) => {
let curPass = req.body.password;
var pass_hash = "";
User.findOne({email: req.body.email},
(err, users)=>{
if(err){
res.json({success: false, msg: "Invalid", data: []});
}
if(users){
pass_hash = users.password_hash;
verification = password_hash.verify(curPass, pass_hash);
if(verification){
// token
const payload = {
role: users.role,
user_id: users._id
};
var token = jwt.sign({
exp: Math.floor(Date.now() / 1000) + (60 * 60), // 1 hour
data: payload
}, 'top-secret');
res.json({success: true, msg: "Login Successful", token: token});
}
else{
res.json({success: false, msg: "Invalid password", data: []});
}
}
else{
res.json({success: false, msg: "Invalid email id", data: []});
}
});
});

Following is the response sent by the server if the user is valid

{
"success": true,
"msg": "Login Successful",
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAasdagdfxg"
}

The user/client receives an JWT and stores it in the local storage. Now, the client needs to access the profile data of the logged in user from the server. Thus, it makes a request for the data as follows.

https://www.xyz.com/api/userREQUEST HEADERS
token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAasdagdfxg

The server now will authenticate the user and start processing for the response. The authentication is required for most of the routes. Thus we can add it to the use() so that every router function will verify the user first and then process the request. If the token in the header is valid, the payload is decoded and stored in req.decoded variable.

// jwt middleware to verify token
router.use((req, res, next)=>{
var token = req.body.token || req.headers['token'];
if(token){
jwt.verify(token, 'top-secret', (err, decoded)=>{
if(err){
return res.json({success: false, msg: 'Token not valid or expired', data: []});
}
else{
req.decoded = decoded;
next();
}
});
}
else{
return res.status(403).json({success: false, msg: 'No token provided', data: []});
}
})

Thus, the server has now verified the user’s token and ready to process the request and send a response.

// get logged user information
router.get('/user', (req, res) => {
User.find({_id: req.decoded.data.user_id}, (err, user)=>{
if(!err){
res.json({success: true, msg: "", data: user});
}
else{
res.json({success: false, msg: "Invalid user", data: []});
}
}).select('-password_hash');
});

Thus, we implemented a simple but secured and efficient token based authentication using JSON web token.

I have implemented an API which uses token based authentication using MEAN stack. If you are working in the same stack this code may be a useful reference for implementing your own token based authentication

 https://github.com/adipixel/expense-tracker/blob/master/routes/api_route.js

Thank you for reading the article.

--

--