JavaScript

Local Authentication Using Passport in Node.js

Hello. This tutorial will explain authentication in the Node.js applications through the passport module.

1. Introduction

Passport.js is an authentication middleware designed for Nodejs. passport-local uses the passport strategy for authenticating with a username and password. The module helps to authenticate using a username and password in the nodejs applications. If you are interested in reading further about this module take a look at this link.

1.1 Setting up Node.js

To set up Node.js on windows you will need to download the installer from this link. Click on the installer (also include the NPM package manager) for your platform and run the installer to start with the Node.js setup wizard. Follow the wizard steps and click on Finish when it is done. If everything goes well you can navigate to the command prompt to verify if the installation was successful as shown in Fig. 1.

Passport in Node.js - npm installation
Fig. 1: Verifying node and npm installation

2. Local Authentication Using Passport in Node.js

To set up the application, we will need to navigate to a path where our project will reside. For programming stuff, I am using Visual Studio Code as my preferred IDE. You’re free to choose the IDE of your choice.

2.1 Setting up the implementation

Let us write the different files which will be required for practical learning.

2.1.1 Setting up dependencies

Navigate to the project directory and run npm init -y to create a package.json file. This file holds the metadata relevant to the project and is used for managing the project dependencies, script, version, etc. Add the following code to the file wherein we will specify the required dependencies.

package.json

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
{
  "name": "passport-app",
  "version": "1.0.0",
  "description": "",
  "main": "server.js",
  "scripts": {
    "start": "nodemon server.js"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "bcrypt": "^5.0.1",
    "ejs": "^3.1.6",
    "express": "^4.17.1",
    "express-flash": "0.0.2",
    "express-session": "^1.17.2",
    "method-override": "^3.0.0",
    "passport": "^0.4.1",
    "passport-local": "^1.0.0"
  },
  "devDependencies": {
    "dotenv": "^10.0.0",
    "nodemon": "^2.0.12"
  }
}

To download the dependencies navigate to the directory path containing the file and use the npm install command. If everything goes well the dependencies will be loaded inside the node_modules folder and you are good to go with the further steps.

2.1.2 View – Creating welcome screen

In the root folder create a folder named views and add the following content to the index.ejs. This screen will be responsible to show the welcome page after successful authentication.

index.ejs

1
2
3
4
<h1>Hi <%= name %></h1>
<form action="/logout?_method=DELETE" method="POST">
  <button type="submit">Sign Out</button>
</form>

2.1.3 View – Creating login screen

In the root folder create a folder named views and add the following content to the login.ejs. This screen will be responsible for the login.

index.ejs

01
02
03
04
05
06
07
08
09
10
11
12
13
14
<h1>Login</h1>
<% if (messages.error) { %> <%= messages.error %> <% } %>
<form action="/login" method="POST">
  <div>
    <label for="email">Email</label>
    <input type="email" id="email" name="email" required />
  </div>
  <div>
    <label for="password">Password</label>
    <input type="password" id="password" name="password" required />
  </div>
  <button type="submit">Login</button>
</form>
<a href="/register">Sign up</a>

2.1.4 View – Creating registration screen

In the root folder create a folder named views and add the following content to the login.ejs. This screen will be responsible for the registration of new users.

index.ejs

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
<h1>Register</h1>
<form action="/register" method="POST">
  <div>
    <label for="name">Name</label>
    <input type="text" id="name" name="name" required />
  </div>
  <div>
    <label for="email">Email</label>
    <input type="email" id="email" name="email" required />
  </div>
  <div>
    <label for="password">Password</label>
    <input type="password" id="password" name="password" required />
  </div>
  <button type="submit">Register</button>
</form>
<a href="/login">Login</a>

2.1.5 Creating passport configuration

In the root folder add the following content to the configuration file. The file will be responsible to configure the strategy using a username and password. The strategy will also require a callback that will accept the credentials and calls a done(…) method to provide the user details.

passport-config.js

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// adding passport related configuration
 
const LocalStrategy = require("passport-local").Strategy;
const bcrypt = require("bcrypt");
 
function initialize(passport, getUserByEmail, getUserById) {
  const authenticateUser = async (email, password, done) => {
    const user = getUserByEmail(email);
    if (user == null) {
      return done(null, false, { message: "User not found" });
    }
 
    try {
      if (await bcrypt.compare(password, user.password)) {
        return done(null, user);
      } else {
        return done(null, false, { message: "Invalid credentials" });
      }
    } catch (e) {
      return done(e);
    }
  };
 
  passport.use(new LocalStrategy({ usernameField: "email" }, authenticateUser));
  passport.serializeUser((user, done) => done(null, user.id));
  passport.deserializeUser((id, done) => {
    return done(null, getUserById(id));
  });
}
 
module.exports = initialize;

2.1.6 Creating controller

In the root folder add the following content to the index file. The file will be responsible to initialize the imports, routes, and specify the passport configuration to authenticate the requests. Remember to create a .env file at the same location and specify the sensitive information such as session-secret, application port number, etc.

server.js

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
if (process.env.NODE_ENV !== "production") {
  require("dotenv").config();
}
 
// imports
const express = require("express");
const app = express();
const bcrypt = require("bcrypt");
const passport = require("passport");
const flash = require("express-flash");
const session = require("express-session");
const methodOverride = require("method-override");
 
// todo - add external db support
const users = [];
 
// configuring and initializing passport
const initializePassport = require("./passport-config");
initializePassport(
  passport,
  (email) => users.find((user) => user.email === email),
  (id) => users.find((user) => user.id === id)
);
 
app.set("view-engine", "ejs");
app.use(express.urlencoded({ extended: false }));
app.use(flash());
app.use(
  session({
    secret: process.env.SESSION_SECRET || "8unto0n4oc7903zm",
    resave: false,
    saveUninitialized: false,
  })
);
app.use(passport.initialize());
app.use(passport.session());
app.use(methodOverride("_method"));
 
// routes
 
// welcome page
// display greetings message for the user and logout button
app.get("/", checkAuthenticated, (req, res) => {
  res.render("index.ejs", { name: req.user.name });
});
 
// login page
app.get("/login", checkNotAuthenticated, (req, res) => {
  res.render("login.ejs");
});
 
app.post(
  "/login",
  checkNotAuthenticated,
  passport.authenticate("local", {
    successRedirect: "/",
    failureRedirect: "/login",
    failureFlash: true,
  })
);
 
// new user sign-up page
app.get("/register", checkNotAuthenticated, (req, res) => {
  res.render("register.ejs");
});
 
app.post("/register", checkNotAuthenticated, async (req, res) => {
  try {
    const hashedPassword = await bcrypt.hash(req.body.password, 10);
    users.push({
      id: "_" + Math.random().toString(36).slice(2),
      name: req.body.name,
      email: req.body.email,
      password: hashedPassword,
    });
 
    res.redirect("/login");
  } catch (e) {
    // console.log(e);
    res.redirect("/redirect");
  }
 
  // check if the user is successfully added to array
  // console.log(users);
});
 
// logout of the application
app.delete("/logout", (req, res) => {
  req.logOut();
  res.redirect("/login");
});
 
// util methods
 
// only authenticated user should enter index page
function checkAuthenticated(req, res, next) {
  if (req.isAuthenticated()) {
    return next();
  } else {
    res.redirect("/login");
  }
}
 
// unauthenticated user should not enter index page
function checkNotAuthenticated(req, res, next) {
  if (req.isAuthenticated()) {
    return res.redirect("/");
  }
  next();
}
 
// start server
const port = process.env.APPLICATION_PORT || 6001;
app.listen(port, () => {
  console.log("Server listening at http://localhost:%s", port);
});

3. Run the Application

To run the application navigate to the project directory and enter the following command as shown in Fig. 2. If everything goes well the application will be started successfully on a port number read from the .env file or 6001.

Passport in Node.js - starting the app
Fig. 2: Starting the application

4. Demo

Once the application is started successfully navigate to the following url to show the login screen. You can click on the signup button for creating a new user and play around with the application after that. In this tutorial, I have also added some of the basic validations like user not found and invalid credentials.

Endpoint

That is all for this tutorial and I hope the article served you with whatever you were looking for. Happy Learning and do not forget to share!

5. Summary

In this tutorial, we learned about the passport module and how to create a simple login application with the help of passport-local dependency. You can download the source code and the postman collection from the Downloads section.

6. Download the Project

This was a tutorial to implement local authentication using a passport module in a nodejs application.

Download
You can download the full source code of this example here: Local Authentication Using Passport in Node.js
Do you want to know how to develop your skillset to become a Java Rockstar?
Subscribe to our newsletter to start Rocking right now!
To get you started we give you our best selling eBooks for FREE!
1. JPA Mini Book
2. JVM Troubleshooting Guide
3. JUnit Tutorial for Unit Testing
4. Java Annotations Tutorial
5. Java Interview Questions
6. Spring Interview Questions
7. Android UI Design
and many more ....
I agree to the Terms and Privacy Policy

Yatin Batra

An experience full-stack engineer well versed with Core Java, Spring/Springboot, MVC, Security, AOP, Frontend (Angular & React), and cloud technologies (such as AWS, GCP, Jenkins, Docker, K8).
Subscribe
Notify of
guest


This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Back to top button