Authentication and Authorization in Node.js

Authentication and Authorization in Node.js

03 Jul 2024
Advanced
19.1K Views
23 min read
Learn with an interactive course and practical hands-on labs

Node.js Course

Previously we have learned how to create JSON Web Token (JWT) by demo login data, passed through request header to verify user by using middleware. Before starting with this post it’s recommended to overview previous post on ” Token-Based Authentication In Node.js Using JWT”.In this article, we are going to learn how to perform user authentication using “Passport” then create JWT token to verify user with access permission on each request. We are going to use MSSQL server for database operations. Previously we have tested the sample application using postman, in this post we are going to configure handlebars as view engine to prepare user interface for user operations.

Download the previous sample from above link to get started with or you may start with a new sample by getting help from this post “Getting Started with ExpressJS”. I am going to use the previous sample application and make the necessary changes in it to configure the view engine with further authentication and authorization process step by step. First, let’s clarify the new term called “Passport”.

Read More - Advanced Node JS Interview Questions and Answers

What is passport.js?

According to passportjs.org : "Passport is authentication middleware for Node. It is designed to serve a singular purpose: authenticate requests." Simply we can say passport is only for authenticate user, that has different authentication options like local and third party (Facebook, Twitter, Github etc). We are going to implement local authentication in our sample application using passport local strategy. Overview the full process from following diagram.

Let’s get started with package installation and implementing passport for authentication. Later we will learn how to implement the authorization based on token and custom user permission.

Authentication

First install all required package using following command:

 
“npm install express-handlebars mssql nodemon passport passport-local”

Passport

After successful package installation go to app.js, enable passport module with following lines of code.

 
var passport = require('passport');
app.use(passport.initialize());

Handlebars

Let’s configure view engine, in app.js register the view engine with the following code snippet. As you can see from below code sample we have commented the auto generated view engine. Here app.engine() is registering the template engine to our application, then set the engine as hbs using app.set() function.

 
var exphbs = require('express-handlebars');

// view engine setup
/* app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade'); */

app.engine('.hbs', exphbs({ defaultLayout: 'main', extname: '.hbs' }));
app.set('view engine', '.hbs');

For more information on handlebars, follow the link : https://www.npmjs.com/package/express-handlebars Add new layout page with the extension of .hbs in views>layouts folder, then copy paste below html to the newly created file.

Main Layout

As you can see the main layout is nothing but a HTML page with render section {{body}}, where other pages going to render with different route path.

 
 <!DOCTYPE html>
 <html>
 
 <head>
 <title>{{title}}</title>
 <meta name="viewport" content="width=device-width, initial-scale=1">
 <link rel="stylesheet" href="/stylesheets/bootstrap.min.css" crossorigin="anonymous">
 <link rel='stylesheet' href='/stylesheets/style.css' />
 </head>
 
 <body>
 <div class="container">
 {{{body}}}
 </div>
 </body>

 </html>

Index Route

Following code snippet will render the index.hbs page on application startup with passing object.

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

/* GET home page. */
router.get('/', function (req, res, next) {
 res.render('index', { title: 'Welcome to ExpressJS + Passport + JSON Web Token (JWT)' });
});

module.exports = router;

Let’s modify the index page with the below HTML code sample.

Index page

 
 <div class="container">
 <div class="row">
 <h3>{{ this.title }} <img src="../images/jwt.png" alt="" width="30px"></h3>
 <hr>
 <a href="/users" class="btn btn-warning">User Login </a>
 <hr>
 <p><b>From jwt.io:</b> JSON Web Token (JWT) is an open standard (RFC 7519) that defines a compact and
 self-contained way for
 securely transmitting information between parties as a JSON object. This information can be verified and
 trusted because it is digitally signed. JWTs can be signed using a secret (with the HMAC algorithm) or a
 public/private key pair using RSA or ECDSA.</p>
 <img src="../images/process.png" alt="" width="700px">
 <br><br>
 <p><b>From passportjs.org:</b> Passport is authentication middleware for Node. It is designed to serve a
 singular purpose: authenticate requests.</p>
 </div>
 </div>

Next create a login page where user can submit form and login by providing login details. Copy paste below code sample to login page.

Login Page

 
 <div class="container">
 <form action="/users" method="POST">
 <div class='row'>
 <h3>User Login</h3>
 <hr>
 <div class='col-sm-4'>
 <div class='form-group'>
 <label for="username">User Name</label>
 <input class="form-control" id="username" name="username" size="250" type="text" required="true" />
 </div>
 </div>
 <div class='col-sm-4'>
 <div class='form-group'>
 <label for="password">Password</label>
 <input class="form-control" id="password" name="password" required="true" size="250" type="password" />
 </div>
 </div>
 </div>
 <div class='row'>
 <div class="col-md-1">
 <button type="button" class="btn btn-warning" onclick="location.href='/';">Back</button>
 </div>
 <div class="col-md-1">
 <button type="button" class="btn btn-danger" onclick="location.href='/users';">Reset</button>
 </div>
 <div class="col-md-2">
 <button type="submit" class="btn btn-success">Login</button>
 </div>
 </div>
 </form>
 </div>

In user.js file, change previous response by rendering “users” view with empty object passing.

 
/* GET users listing. */
router.get('/', function (req, res, next) {
 /* res.send('respond with a resource'); */
 res.render('users', {});
});

Go to package.json then add new script object "dev": "nodemon ./bin/www" like below image

Nodemon will automatically restart our application when we make any save changes to our application.Let’s run the application using command “npm run dev” like following image

As you can see the application has run with port 3000. Go to brouser then browse with URL “http://localhost:3000” From home page, click on button “User Login” to see below login screen:

As you can see the login page is rendered with user login form. So far we have successfully implemented the view engine to our sample application. Next we are going to authenticate user by using the login form with local passport authentication. Create a database by using below SQL script.

Create Database

 
USE [master]
GO
/****** Object: Database [ExpressJWTPass] Script Date: 9/14/2018 11:38:36 AM ******/
CREATE DATABASE [ExpressJWTPass]
GO
USE [ExpressJWTPass]
GO
/****** Object: Table [dbo].[users] Script Date: 9/14/2018 11:38:36 AM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[users](
 [userId] [int] NOT NULL,
 [userName] [nvarchar](50) NULL,
 [password] [nvarchar](50) NULL,
 [usertype] [nvarchar](50) NULL,
 [canEdit] [bit] NULL,
 [canDelete] [bit] NULL,
 [canCreate] [bit] NULL,
 [canView] [bit] NULL,
 CONSTRAINT [PK_users] PRIMARY KEY CLUSTERED 
(
 [userId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
INSERT [dbo].[users] ([userId], [userName], [password], [usertype], [canEdit], [canDelete], [canCreate], [canView]) VALUES (1, N'shashangka', N'12345', N'admin', 1, 1, 1, 1)
INSERT [dbo].[users] ([userId], [userName], [password], [usertype], [canEdit], [canDelete], [canCreate], [canView]) VALUES (2, N'ishani', N'12345', N'editor', 0, 0, 1, 1)

/****** Object: StoredProcedure [dbo].[GetUserAuthentication] Script Date: 9/14/2018 11:38:36 AM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author: <Author,,Name>
-- Create date: <Create Date,,>
-- Description: <Description,,>
-- =============================================
CREATE PROCEDURE [dbo].[GetUserAuthentication]
 -- Add the parameters for the stored procedure here
 @username nvarchar(50),
 @password nvarchar(50)
AS
BEGIN
 -- SET NOCOUNT ON added to prevent extra result sets from
 -- interfering with SELECT statements.
 SET NOCOUNT ON;

 -- Insert statements for procedure here
 SELECT [userId],[userName],[usertype]--,[canEdit],[canDelete],[canCreate],[canView]
 FROM [dbo].[users]
 WHERE [userName] = @username AND [password] = @password
END
GO

For now we are done with the database, next we will create a service module to interact with database.

Data Service

Create a folder named “data”, then add the service module named “dbService.js”. Copy paste below code snippet to the newly created file. Change the config section according to your SQL server details. Here the max pool is 10 & min is 0 & default connection timeout is 30000 millisecond.

 
var dbConfig = {
 user: "user",
 password: "password",
 server: " YourDatabaseServer",
 database: " YourDatabaseName",
 port : 1433,
 pool: {
 max: 10,
 min: 0,
 idleTimeoutMillis: 30000
 }
};

Get more details on Pool by following link :https://github.com/coopernurse/node-pool

ConnectionPool

In query execute section create connection object using connectionpool.

 
const conn = new mssql.ConnectionPool(dbConfig);

If the connection is ok then perform database operation using the opened connection.

 
const req = new mssql.Request(conn);
Finally the service
 
var mssql = require('mssql');

var dbConfig = {
 user: "sa",
 password: "sa@12345",
 server: "DESKTOP-DUDGUJT\\SQLEXPRESS",
 database: " ExpressJWTPass",
 port : 1433,
 pool: {
 max: 10,
 min: 0,
 idleTimeoutMillis: 30000
 }
};

var executeQuery = function (sql, res) {
 const conn = new mssql.ConnectionPool(dbConfig);
 conn.connect().then(function () {
 const req = new mssql.Request(conn);
 req.query(sql).then(function (data) {
 res(data);
 }).catch(function (err) {
 res(null, err);
 })
 }).catch(function (err) {
 res(null, err);
 })
}

module.exports = {
 executeQuery
}

Get more details on SQL connection by following link: https://www.npmjs.com/package/mssql#connections-1

In the next portion we are going to check user login details from database, if the user is valid then we are creating the JWT and passing it back to the client to store it. By using cookies we are storing the user information and generated token to client machine so that client can use it on each request to revalidate the token and get API access according to user access permission.

Authentication

Let’s add passport.js file for passport local authentication, include the required module packages, as we are using passport local strategy to authenticate the user so we have included the “passport-local” module package by creating object named “strategy”.

passport.js
 
var passport = require('passport');
var strategy = require('passport-local');
var dbService = require('../data/dbService');
let jwt = require('jsonwebtoken');

passport.use(new strategy({ session: false }, function (username, password, callback) {
 //Stored Procedure
 var query = "[GetUserAuthentication] '" + username + "', '" + password + "'";

 //Get Data From Database
 dbService.executeQuery(query, function (data, err) {
 if (err) {
 callback(null, err);
 } else {
 var result = data.recordset
 if (result.length> 0) {
 let token = jwt.sign(result[0], global.config.secretKey, {
 algorithm: global.config.algorithm,
 /* expiresIn: '1m' */
 });
 callback({ user: result[0], token: token });
 }
 else {
 callback({ user: null, token: null });
 }
 }
 });
}));

module.exports = passport;

From the above code sample, using “passport.use()” function we are going to validate user bypassing local account details. We are not using any session to storing authentication information by defining session value false. If the user is valid then a token is generated by JWT. The generated token is stored in the client machine for further API request. Next client is submitting the post request with user login data for authentication using “passport.authenticate()” function. This is where we are storing the returned token and logged user information in client browser after successful authentication.

HTTP Login POST
 
/* Post users Login. */
router.post('/', function (req, res, next) {
 passport.authenticate('local', function (data, err) {
 if (err) {
 res.redirect('/users?status=' + encodeURIComponent('Error Login!!'));
 console.log(err.name + ':' + err.message);
 } else {
 if (data.user != null) {
 res.cookie('jwtoken', data.token);
 res.cookie('loggeduser', data.user);
 res.redirect('/');
 }
 else {
 res.redirect('/users?status=' + encodeURIComponent('Incorrect login details!!'));
 }
 }
 })(req, res, next);
});

Let’s modify our index page with the below code to display the logged user details with logout button.

Index Page
 
 {{#if user }}
 <h4>Hello, {{ user.userName }} [{{ user.usertype }}]</h4>
 <a href="/users/logout" class="btn btn-danger">Logout</a>
 {{ else }}
 <a href="/users" class="btn btn-warning">User Login </a>
 {{/if}}

Using below code sample, on user logout button click application is clearing the stored information and redirecting to user login page.

HTTP Logout GET
 
// GET user Logout
router.get('/logout', function (req, res, next) {
 res.clearCookie('jwtoken');
 res.clearCookie('loggeduser');
 res.redirect('/users');
});

Let’s test the application at this stage with user authentication, go to login page fill the login information.

As you can see from above image, user login successful with displaying the logged user details. Now go to application tab in browser to see the cookies where the token and logged user information is stored.

Next section we are going to manage list of customers in database by particular user access authorization. This is where we are protecting the API’s from unauthorized access by using the token which is going to validate on each request.

Authorization

Let’s create a customer table to store customer’s information. Below script will create the required table and stored procedure. Copy paste the script to query window then execute.

 
USE [ExpressJWTPass]
GO
/****** Object: Table [dbo].[customers] Script Date: 9/14/2018 11:38:36 AM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[customers](
 [customerId] [int] NOT NULL,
 [customerName] [nvarchar](50) NULL,
 [customerContact] [nvarchar](50) NULL,
 [customerEmail] [nvarchar](50) NULL,
 CONSTRAINT [PK_customers] PRIMARY KEY CLUSTERED 
(
 [customerId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
/****** Object: StoredProcedure [dbo].[DeleteCustomersByID] Script Date: 9/14/2018 11:38:36 AM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author: <Author,,Name>
-- Create date: <Create Date,,>
-- Description: <Description,,>
-- =============================================
CREATE PROCEDURE [dbo].[DeleteCustomersByID]
 -- Add the parameters for the stored procedure here
 @customerId INT
AS
BEGIN
 -- SET NOCOUNT ON added to prevent extra result sets from
 -- interfering with SELECT statements.
 SET NOCOUNT ON;

 -- Insert statements for procedure here
 DELETE FROM [dbo].[customers] WHERE [customerId] = @customerId
END
GO
/****** Object: StoredProcedure [dbo].[GetCustomers] Script Date: 9/14/2018 11:38:36 AM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author: <Author,,Name>
-- Create date: <Create Date,,>
-- Description: <Description,,>
-- =============================================
CREATE PROCEDURE [dbo].[GetCustomers]
 -- Add the parameters for the stored procedure here
 
AS
BEGIN
 -- SET NOCOUNT ON added to prevent extra result sets from
 -- interfering with SELECT statements.
 SET NOCOUNT ON;

 -- Insert statements for procedure here
 SELECT [customerId],[customerName],[customerContact],[customerEmail]
 FROM [dbo].[customers]
END
GO
/****** Object: StoredProcedure [dbo].[GetCustomersByID] Script Date: 9/14/2018 11:38:36 AM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author: <Author,,Name>
-- Create date: <Create Date,,>
-- Description: <Description,,>
-- =============================================
CREATE PROCEDURE [dbo].[GetCustomersByID]
 -- Add the parameters for the stored procedure here
 @customerId INT
AS
BEGIN
 -- SET NOCOUNT ON added to prevent extra result sets from
 -- interfering with SELECT statements.
 SET NOCOUNT ON;

 -- Insert statements for procedure here
 SELECT [customerId],[customerName],[customerContact],[customerEmail]
 FROM [dbo].[customers] WHERE [customerId] = @customerId
END
GO

/****** Object: StoredProcedure [dbo].[GetUserAuthorization] Script Date: 9/14/2018 11:38:36 AM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[GetUserAuthorization]
 @Userid NVarchar(250),
 @Methodtype NVarchar(250)
AS
BEGIN
 -- SET NOCOUNT ON added to prevent extra result sets from
 -- interfering with SELECT statements.
 SET NOCOUNT ON;

 -- Insert statements for procedure here
 SELECT CASE WHEN result = 1 THEN 'true' ELSE 'false' END AS permission FROM
 (
 SELECT CASE
 WHEN @Methodtype = 'GET' THEN [CanView]
 WHEN @Methodtype = 'POST' THEN [canCreate]
 WHEN @Methodtype = 'PUT' THEN [canEdit]
 WHEN @Methodtype = 'DELETE' THEN [CanDelete]
 ELSE 0
 END AS result

 FROM [dbo].[users] WHERE [userId] = @Userid
 )AUTH 
END

--EXEC GetUserAuthorization '2', 'POST'
GO
/****** Object: StoredProcedure [dbo].[SaveCustomer] Script Date: 9/14/2018 11:38:36 AM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author: <Author,,Name>
-- Create date: <Create Date,,>
-- Description:<Description,,>
-- =============================================
CREATE PROCEDURE [dbo].[SaveCustomer]
 -- Add the parameters for the stored procedure here
 @customerId INT,
 @customerName Nvarchar(50),
 @customerContact Nvarchar(50),
 @customerEmail Nvarchar(50)
AS
BEGIN
 -- SET NOCOUNT ON added to prevent extra result sets from
 -- interfering with SELECT statements.
 SET NOCOUNT ON;

 IF(@customerId>0)
 BEGIN
 Update [dbo].[customers]
 SET [customerName] = @customerName,
 [customerContact] = @customerContact,
 [customerEmail] = @customerEmail
 Where [customerId] = @customerId
 END
 ELSE
 BEGIN
 DECLARE @custId INT
 SET @custId = ISNULL(((SELECT MAX(customerId) FROM [dbo].[customers])+1),'1');

 -- Insert statements for procedure here
 Insert Into [dbo].[customers]
 ([customerId],[customerName],[customerContact],[customerEmail])
 Values
 (@custId,@customerName,@customerContact,@customerEmail)
 END
END
GO

After successful script execution let’s create a customer data service to perform CRUD operations in database. Go to data folder then create “customerService.js” file.Copy paste below code sample to newly created CRUD service module.

Customer Data Service

 
var dbService = require('../data/dbService');

var getData = function (req, res, callback) {
 //Stored Procedure
 let query = "[GetCustomers]";

 //Database Query
 dbService.executeQuery(query, function (data, err) {
 if (err) {
 callback(null, err);
 } else {
 callback(data);
 }
 });
};

var getDataById = function (req, res, callback) {
 let customerId = req.params.id; let status = req.query.status;

 //Stored Procedure
 var query = "[GetCustomersByID] " + customerId + "";

 //Database Query
 dbService.executeQuery(query, function (data, err) {
 if (err) {
 callback(null, err);
 } else {
 callback(data);
 }
 });
};

var postData = function (req, res, callback) {
 let customerId = 0;
 if (isNaN(parseInt(req.body.customerId)))
 customerId = 0;
 else
 customerId = parseInt(req.body.customerId);

 //Stored Procedure
 var query = "[SaveCustomer] " + customerId + ", '" + req.body.customerName + "', '" + req.body.customerContact + "', '" + req.body.customerEmail + "'";

 //Database Query
 dbService.executeQuery(query, function (data, err) {
 if (err) {
 callback(null, err);
 } else {
 callback(data);
 }
 });
};

var deleteData = function (req, res, callback) {
 let customerId = req.params.id;

 //Stored Procedure
 var query = "[DeleteCustomersByID] " + parseInt(customerId) + "";

 //Database Query
 dbService.executeQuery(query, function (data, err) {
 if (err) {
 callback(null, err);
 } else {
 callback(data);
 }
 });
};

module.exports = {
 getData,
 getDataById,
 postData,
 deleteData
};

Verify Token

Let’s modify the existing token verification module for verify process. This is where the stored token is retrieved by “req.cookies.jwtoken” for use, in previous example we used “x-access-token” to pass token string.Here if token is valid, the authorization is done with the below access permission retrieving from database based on user and given permission.Below sample access permission data worked with different logged user for multiple operations.

verifytoken.js
 
var express = require('express');
var router = express.Router();
var dbService = require('../data/dbService');
var jwt = require('jsonwebtoken');

router.use(function (req, res, next) {
 var token = req.headers['x-access-token'] || req.cookies.jwtoken;
 var httpMethod = null; //var httpMethod = req.method;
 var originalUrl = req.originalUrl;

 if (originalUrl.includes("save")) httpMethod = 'POST';
 else if (originalUrl.includes("edit")) httpMethod = 'PUT';
 else if (originalUrl.includes("delete")) httpMethod = 'DELETE';
 else httpMethod = 'GET';

 if (token) {
 jwt.verify(token, global.config.secretKey,
 {
 algorithm: global.config.algorithm

 }, function (err, decoded) {
 if (err) {
 let errordata = {
 message: err.message,
 expiredAt: err.expiredAt
 };
 console.log(errordata);
 return res.render('customers', { title: 'Unauthorized Access', status: 'Token Expired at ' + err.expiredAt });
 }
 req.decoded = decoded;

 //Stored Procedure
 var query = "[GetUserAuthorization] '" + decoded.userId + "', '" + httpMethod + "'";

 //Get Authorization From Database
 dbService.executeQuery(query, function (data, err) {
 if (err) {
 console.log(err.name + ':' + err.message);
 } else {
 var result = data.recordset[0].permission;
 if (result == 'true') {
 next();
 }
 else {
 console.log('Unauthorized Access!!');
 if (httpMethod == 'GET') {
 return res.redirect('/');
 }
 else {
 return res.redirect('/customers?status=' + encodeURIComponent('Operation Restricted!!'));
 }
 }
 }
 });
 });
 } else {
 return res.redirect('/');
 }
});

module.exports = router;

We are almost done with our authorization process. Modify the existing customer routes by following code sample. As you can see the “verifyToken” middleware is passed as argument with the each HTTP request method to verify the user access validity. If the request is valid then application is going to proceed otherwise it’ll response redirect with status message passed by query string.

Customer Route

 
var express = require('express');
var router = express.Router();
var dbService = require('../data/dbService');
var custService = require('../data/customerService');
let verifyToken = require('./verifytoken');

/* GET customers listing. */
router.get('/', verifyToken, function (req, res, next) {
 let status = req.query.status;

 //Service Call
 custService.getData(req, res, function (data, err) {
 if (err) {
 res.render('customers', { message: 'Error Loading Data!!' });
 console.log(err.name + ':' + err.message);
 } else {
 res.render('customers', { customerdata: data.recordset, message: status });
 }
 });

});

/* GET customers ByID */
router.get('/edit/:id', verifyToken, function (req, res, next) {
 let status = req.query.status;

 custService.getDataById(req, res, function (data, err) {
 if (err) {
 res.render('customers', { message: 'Error Binding Data!!' });
 console.log(err.name + ':' + err.message);
 } else {
 var customeredit = data.recordset[0];

 //Service Call
 custService.getData(req, res, function (data, err) {
 if (err) {
 res.render('customers', { message: 'Error Loading Data!!' });
 console.log(err.name + ':' + err.message);
 } else {
 res.render('customers', { customerdata: data.recordset, customer: customeredit, message: status });
 }
 });
 }
 });
});

/* POST customer */
router.post('/save', verifyToken, function (req, res, next) {
 let status = req.query.status;

 //Service Call
 custService.postData(req, res, function (data, err) {
 if (err) {
 res.render('customers', { message: 'Error Saving Data!!' });
 console.log(err.name + ':' + err.message);
 } else {
 res.redirect('/customers');
 }
 });
});

/* DELETE Delete customers */
router.get("/delete/:id", verifyToken, function (req, res) {
 let status = req.query.status;

 //Service Call
 custService.deleteData(req, res, function (data, err) {
 if (err) {
 res.render('customers', { message: 'Error Deleting Data!!' });
 console.log(err.name + ':' + err.message);
 } else {
 res.redirect('/customers');
 }
 });
});

module.exports = router;

Let’s add an access button in index page navigating to customer route

 
<a href="/customers" class="btn btn-primary">Manage Customers</a>

Customer Page

Finally create customer page in views folder by naming it “customers.hbs”, copy paste below code sample

 
 <div class="container">
 <form action="/customers/save" method="POST">
 <div class='row'>
 <h3>Customer Info {{#if message }} - {{message}}{{/ if }}</h3>
 <hr>
 <input type="hidden" name="customerId" value="{{customer.customerId}}" />
 <div class='col-sm-4'>
 <div class='form-group'>
 <label for="customerName">Customer Name</label>
 <input class="form-control" id="customerName" name="customerName" size="250" type="text" required="true"
 value="{{customer.customerName}}" />
 </div>
 </div>
 <div class='col-sm-4'>
 <div class='form-group'>
 <label for="customerContact">Contact</label>
 <input class="form-control" id="customerContact" name="customerContact" required="true" size="250"
 value="{{customer.customerContact}}" type="text" />
 </div>
 </div>
 <div class='col-sm-4'>
 <div class='form-group'>
 <label for="customerEmail">Email</label>
 <input class="form-control" id="customerEmail" name="customerEmail" required="true" size="250" type="email"
 value="{{customer.customerEmail}}" />
 </div>
 </div>
 </div>
 <div class='row'>
 <div class="col-md-1">
 <button type="button" class="btn btn-warning" onclick="location.href='/';">Back</button>
 </div>
 <div class="col-md-1">
 <button type="button" class="btn btn-danger" onclick="location.href='/customers';">Reset</button>
 </div>
 <div class="col-md-2">
 <button type="submit" class="btn btn-success">Submit</button>
 </div>
 </div>
 </form>
 
 <div class='row'>
 {{#if customerdata }}
 <h3>Customer List</h3>
 <hr>
 <table class="table table-striped">
 <thead>
 <tr>
 <th>Id</th>
 <th>Customer Name</th>
 <th>Contact</th>
 <th>Email</th>
 <th>Option</th>
 </tr>
 </thead>
 {{#each customerdata}}
 <tr>
 <td>{{this.customerId}}</td>
 <td>{{this.customerName}}</td>
 <td>{{this.customerContact}}</td>
 <td>{{this.customerEmail}}</td>
 <td>
 <a href="/customers/edit/{{this.customerId}}" title="Edit Record" class="btn btn-primary btn-xs pull-right">
 Edit
 </a>
 <a href="/customers/delete/{{this.customerId}}" title="Delete Record" class="btn btn-danger btn-xs pull-right" onclick="return confirm('You are about to delete {{this.customerName}}, are you sure?')">
 Delete
 </a>
 </td>
 </tr>
 {{/each}}
 </table>
 {{/if}}
 </div>
 </div>

Yes, we are done with our authorization process, next we are going to test the user access by different logged user.After successful login click on “Manage Customers“ button to navigate customer page.

As you can see the customer page is displayed with customer form, create a new customer by submitting with providing customer details.

If the user have the create permission, it will save the customer to database and list the customer in below table like below screen.

Otherwise it will response with “Operation Restriction” message.

So far, we have seen the whole process of authentication and authorization step by step, learned how we can protect API’s from unwanted access, let’s summarize the process and learning.

Summary

In this article, I have covered the following things

  • Configuring view engine

  • Enabled and used passport local for authentication.

  • Generate JWT on passport authentication.

  • Using JWT to secure ExpressJS API

  • Using router level middleware

  • Using cookies in browser to stored logged information.

  • Retrieving values from cookies.

  • Using custom user authorization on token validation

  • Hope the article will help you to create secured API’s using Passport and JWT in ExpressJS application.

Take our Nodejs skill challenge to evaluate yourself!

In less than 5 minutes, with our skill challenge, you can identify your knowledge gaps and strengths in a given skill.

GET FREE CHALLENGE

Share Article
About Author
Shashangka Shekhar Mandal (An Author and Software Architect)

He is a passionate Software development professional with more than six years of experience who believe in the desire of learning & also love to sharing knowledge’s, currently working as a Software Architect. He has solid skills & experience in C#, .Net, ASP.Net, MVC, WebAPI, SignalR, Entity Framework, LINQ, ADO.Net, JavaScript, jQuery, Angular, NodeJS, ExpressJS and MySQL. Since 2011 he involved himself with software development and loves to explore new technologies and sharing those experiences with the community.
Accept cookies & close this