Chapter 4: The MEAN Stack Security
Activity 11: Securing the RESTful API
File name: userController.js
Live link: http://bit.ly/2DJEs5S
Create an admin user model by creating a file named userModel.js inside the api folder and input the following code:
const mongoose = require("mongoose"), / loading modules bcrypt = require('bcryptjs'), Schema = mongoose.Schema; const UserSchema = new Schema({ / Schema Instance fullName: { type: String, trim: true, required: true }, email: { type:String, unique:true, lovercase:true, trim:true, required:true } , hash_password: { type:String, required:true }, createdOn: { type: Date, default: Date.now } }); UserSchema.methods.comparePassword = function(password){ /password confirmation return bcrypt.compareSync(password, this.hash_password); } module.exports = mongoose.model("User", UserSchema); /user modelCreate an admin user controller by creating a file called userController.js inside the controllers/api folder input using the following code:
const User = require("../models/userModel"); / Import userModel, jwt = require('jsonwebtoken'), / load jasonwebtoken module bcrypt = require('bcryptjs'); / load bcryptjs module for password hashing exports.register = (req, res) => { / exportable function to register new user let newUser = new User(req.body); newUser.hash_password = bcrypt.hashSync(req.body.password, 10); newUser.save((err, user) => { if (err) { res.status(500).send({ message: err }); } user.hash_password = undefined; res.status(201).json(user); }); }; /[…] exports.loginRequired = (req, res, next) => { if (req.user) { res.json({ message: 'Authorized User!'}); next(); } else { res.status(401).json({ message: 'Unauthorized user!' }); } };Update the route file (articleListRoutes.js) in the routes directory (server/api/controllers) with the following code:
'use strict'; module.exports = function(app) { var articleList = require('../controllers/articleListController'); var userHandlers = require('../controllers/userController'); / articleList Routes app .route("/articles") .get(articleList.listAllArticles) .post(userHandlers.loginRequired, articleList.createNewArticle); app .route("/article/:articleid") .get(articleList.readArticle) .put(articleList.updateArticle) .delete(articleList.deleteArticle); app .route("/articles/by/:tag") .get(articleList.listTagArticles); app .route("/auth/register") .post(userHandlers.register); app .route("/auth/sign_in") .post(userHandlers.signIn); };Update the server.js (inside the server folder) file with the following code:
'use strict' const express = require("express"); const bodyParser = require("body-parser"); / db instance connection require("./config/db"); var User = require('./api/models/userModel'), jsonwebtoken = require("jsonwebtoken"); const app = express(); const port = process.env.PORT || 3000; app.use(bodyParser.urlencoded({ extended: true })); app.use(bodyParser.json()); /CORS (Cross-Origin Resource Sharing) headers to support Cross-site HTTP requests app.use(function(req, res, next) { res.header('Access-Control-Allow-Origin', '*'); res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,PATCH,OPTIONS'); res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization, Content-Length, X-Requested-With'); / allow preflight if (req.method === 'OPTIONS') { res.send(200); } else { next(); } }); app.use((req, res, next) => { / Verify JWT for user authorization if (req.headers && req.headers.authorization && req.headers.authorization.split(' ')[0] === 'JWT') { jsonwebtoken.verify(req.headers.authorization.split(' ')[1], 'RESTfulAPIs', (err, decode) => { if (err) req.user = undefined; req.user = decode; next(); }); } else { req.user = undefined; next(); } }); / API ENDPOINTS var routes = require('./api/routes/articleListRoutes'); /importing route routes(app); / LISTENING app.listen(port, () => { console.log('Server running at http://localhost:${port}'); });Run the server using node server on the CLI and open Postman for testing.
Test for registration by typing in localhost:3000/auth/register on the address bar. You will obtain the following output:

Figure 4.18: Screenshot for setting the authentication key
Attempt the login required path and post request on localhost:3000/articles. You will obtain the following output:
http://bit.ly/2FXYfki
Create a package.json file and install express, body-parser, mongoose, passport-twitter, and passport by running the following code:
npm init npm install express body-parser mongoose passport-twitter passport express-session -save
Create a server.js (using touch server.js on the CLI) file and import express and body-parser using the following code:
const express = require("express"); const bodyParser = require("body-parser"); const session = require('express-session');Create an Express application, assign a port number, and use the body-parser middleware on the Express application using the following code:
const app = express(); const port = process.env.PORT || 4000; app.use(bodyParser.urlencoded({ extended: true })); app.use(bodyParser.json());Create a config folder using the following code:
mkdir config
Create a database by first creating a file named db.js (using touch db.js on the CLI) in the config folder directory and input the following code:
const mongoose = require("mongoose"); var uri = "mongodb+srv://username:[email protected]/test?retryWrites=true"; const options = { reconnectTries: Number.MAX_VALUE, poolSize: 10 }; / Connect to the database using the following code mongoose.connect(uri, options).then( () => { console.log("Database connection established!"); }, err => { console.log("Error connecting Database instance due to: ", err); } );Create an api directory and three subfolders named controllers, models, and routes using the following code:
mkdir api mkdir – controllers && mkdir – models && mkdir – routes
Create a model file inside the controller directory (using touch userModel.js on the CLI) and then create the schema and model:
const mongoose = require("mongoose"), const Schema = mongoose.Schema; const UserSchema = new Schema({ twitter : { fullName : String, email : String, createdOn: { type: Date, default: Date.now }, }, }); /Create a mongoose model from the Schema mongoose.model("User", UserSchema);Create a passport file inside the config directory (using touch passport.js) and then create a Twitter strategy using the following code:
const TwitterStrategy = require("passport-twitter").Strategy; const mongoose = require('mongoose'), const User = mongoose.model('User'); / Create an exposed function module.exports = function (passport) {} serialize the user for the session passport.serializeUser(function (user, done) { done(null, user.id); }); deserialize the user passport.deserializeUser(function (id, done) { User.findById(id, function (err, user) { done(err, user); }); }); /[…] } else { done(null, user); } }); } )); }Create a route file inside the routes directory (using touch route.js) and then create an exposed function as an exportable module that takes in app and passport using the following code:
module.exports = function(app,passport) { app.get('/auth/twitter', passport.authenticate(' twitter ', {scope:"email"})); app.get('/auth/ twitter /callback', passport.authenticate('twitter', { failureRedirect: '/error' }), function(req, res) { res.redirect('/success'); }); }Update the server.js file with the following code:
/db instance connection require("./config/db"); app.get('/success', (req, res) => res.send("You have successfully logged in")); app.get('/error', (req, res) => res.send("error logging in"));Import and initialize passport using the following code:
const passport = require("passport"); / Authentication configuration app.use(session({ resave: false, saveUninitialized: true, secret: 'bla bla bla' })) app.use(passport.initialize()); app.use(passport.session());Update the API endpoint using the following code:
var routes = require('./api/routes/route'); /importing route routes(app,passport);app.listen(port, () => { console.log('Server running at http://localhost:${port}'); });Run the server (using node server on the CLI), open a browser, and test this by typing in localhost:4000/auth/twitter on the browser address bar. You will obtain the following output:

Figure 4.20: Successful authentication using Twitter