Security in Rest API in Express


Create LearnExpressJSRestAPIWithRealApps folder and select to this folder in Visual Studio Code

Use the following command to install Express.JS:

npm install express --save
npm install body-parser --save
npm install cookie-parser --save
npm install multer --save

Use the following command to install security module:

npm install jwt-simple --save




Create security folder. Inside the security folder create a new file named secret.js. This file contains secret key for creating token.

module.exports = function() {
  return 'learnexpressjsrestapi_secret_key';
}

Inside the security folder create a new file named auth.js. This file contains method generate secket key.

var jwt = require('jwt-simple');

var auth = {
  genToken: function () {
    var expires = this.expiresIn(7); // 7 days
    var token = jwt.encode({
      exp: expires
    }, require('./secret')());
    return {
      token: token,
      expires: expires
    };
  },
  expiresIn: function (numDays) {
    var dateObj = new Date();
    return dateObj.setDate(dateObj.getDate() + numDays);
  }
}

module.exports = auth;

Inside the security folder create a new file named validateRequest.js. This file will check validate API requests.

var jwt = require('jwt-simple');
module.exports = function (req, res, next) {

  var token = (req.body && req.body.access_token)
    || (req.query && req.query.access_token)
    || req.headers['x_access_token'];

  if (token) {
    try {
      var decoded = jwt.decode(token, require('./secret.js')());

      if (decoded.exp <= Date.now()) {
        res.status(400);
        res.json({
          "status": 400,
          "message": "Token Expired"
        });
        return;
      }

      next();

    } catch (err) {
      res.status(401);
      res.json({
        "status": 401,
        "message": "Invalid Token or Key",
        "error": err
      });
    }
  } else {
    res.status(401);
    res.json({
      "status": 401,
      "message": "Invalid Token or Key"
    });
    return;
  }
};




Inside the security folder create a new file named token.api.js

var auth = require('./auth');

var TokenAPI = {
    generate: function (request, response) {
        response.send(auth.genToken());
    }
};

module.exports = TokenAPI;

Inside the security folder create a new file named index.js

var express = require('express');
var router = express.Router();

var TokenAPI = require('./token.api');

router.get('/token/generate', TokenAPI.generate);

module.exports = router;

Create a new folder named api inside the server project. Create demo.api.js file inside api folder contains Rest APIs provides text/plain data for the client

var DemoAPI = {
    work1: function (request, response) {
        response.send('Work 1');
    }
};

module.exports = DemoAPI;

Inside the api folder create a new file named index.js. This file will hold all the routes needed for rest api in server.

var express = require('express');
var router = express.Router();

var DemoAPI = require('./demo.api');

router.get('/demo/work1', DemoAPI.work1);

module.exports = router;

At the root of server project, create a file named server.js. This will be the entry point into node application. This will start the server and listen on a local port

var express = require('express');
var bodyParser = require('body-parser');
var app = express();
app.use(bodyParser.urlencoded({
	extended: true
}));
app.use(bodyParser.json());

app.all('/*', function (req, res, next) {
	res.header("Access-Control-Allow-Origin", "*");
	res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS');
	res.header('Access-Control-Allow-Headers', 'Content-type,Accept,X-Access-Token,X-Key');
	if (req.method == 'OPTIONS') {
		res.status(200).end();
	} else {
		next();
	}
});

app.all('/api/*', [require('./security/validateRequest')]);

app.use('/api', require('./api/index'));

// Test Generate Token
app.use('/security', require('./security/index'));

var server = app.listen(9090, function () {
	var host = server.address().address;
	var port = server.address().port;
	console.log("Server listening at http://%s:%s", host, port)
});




At the root of server project run command: node server.js

Open http://localhost:9090/security/token/generate in your browser to see the result

{"token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE1MTg0NDc5NDE4NDJ9.3XRb2uG_DSaBr5qVeI51AbAfERejONjQJqLM05NCWCk","expires":1518447941842}

Create LearnExpressJSRestAPIWithRealApps_Client folder and select to this folder in Visual Studio Code

Use the following command to install http module

npm install http --save

Create a new folder named api inside the client folder. Create demo.api.js file inside api folder contains method call Rest API from server with token key

var http = require('http');
var BASE_URL = 'http://localhost:9090/api/';

var DemoAPIClient = {
    work1: function (callback) {

        var options = {
            hostname: 'localhost',
            port: 9090,
            path: '/api/demo/work1',
            method: 'GET',
            headers: {
                'x_access_token': 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE1MTg0Mjc3NzY3Mzl9.IKR4rUdfNEJXmMWAM1IwbE5UtMfOMERtmqNKxIjeCjo',
            }
        };

        http.request(options, function (response) {
            var str = '';
            response.on('data', function (chunk) {
                str += chunk;
            });
            response.on('end', function () {
                callback({
                    status: response.statusCode,
                    body: str
                });
            });
            response.on('error', function (error) {
                callback({
                    status: response.statusCode,
                    error: error.message
                });
            });
        }).end();

    }
};

module.exports = DemoAPIClient;




At the root of client project, create a file named client.js. This will call Rest API and display results

var DemoAPIClient = require('./api/demo.api');
DemoAPIClient.work1(function (result) {
    if (result.error) {
        console.log(result.error)
    } else {
        console.log('Status: ' + result.status);
        console.log('Body: ' + result.body);
    }
});

Correct Token Key

Status: 200
Body: Work 1

InCorrect Token Key

Status: 401
Body: {"status":401,"message":"Invalid Token or Key","error":{}}