REST — Token based authentication (jwt)

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

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

Statelessness

Access tokens

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

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.

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store