How to Implement ACL with Passport using Node.js ?
Last Updated :
24 Jul, 2024
Nodejs is an asynchronous event-driven JavaScript runtime, Node.js is designed to build scalable network applications.
Passportjs: Passport is authentication middleware for Node.js. Extremely flexible and modular, Passport can be unobtrusively dropped in to any Express-based web application. A comprehensive set of strategies support authentication using a username and password, Facebook, Twitter, and more. It is widely used by developers to create secure and scalable web applications.
Steps to create ACL with passport using Node.js:
1: Create a Folder with a project name in any IDE (I’m using VS Code): See the below-mentioned folder structure.
Step 1: Open the terminal and type “npm init”. Keep on pressing enter for the default values since this command is used to set up a new npm package. Upon successful installation, it will create a package.json folder.
Step 2: For installing node dependencies, press “npm i express ejs”.
Step 3: For installing dev dependencies, press “npm i –save-dev nodemon dotenv”. Nodemon allows you to restart your server automatically every time anything changes and dotenv allows us to have environment variables that will store under .env file that we can load into the server.
Step 4: Make file “.env” and “.gitignore” as given in the below directory structure.
Â

Folder Structure
.gitignore contains those files that we don’t want to commit to our git repository. Here we have stored .env and node_modules since it contains only the dependencies and .env may contain sensitive information we don’t want to share with the world.

add these to your .env file
Step 5: The last thing that we need to do is set up package.json so that we can start the server. Edit the script section as follows:
Â

Update the script as follows:
Step 6: Now if you press “npm run devStart” in your terminal it will start the server. You should get something like this in your terminal.
Â

No errors in red, all green!
2: Set up our basic express application with the below code in server.js.
JavaScript
// STEP 1: Install all the necessary dependencies
// add the dependencies with the help of require
const express = require('express')
const app = express()
// To run our app on port 3000
app.listen(3000)
But if we run our server after writing this piece of code, we will get the below page on localhost:300

Throws this error
It shows, Cannot GET/ because we haven’t set up any routes for our application yet. Let’s resolve this in step 3.
3: Add the above-mentioned code in server.js and make a folder named views with index.ejs in it.

Â

Output on localhost:3000
4: Install another package using “npm i bcrypt”: bcrypt will allow us to hash passwords and compare hashed passwords to make sure that our application is completely secured.
server.js
JavaScript
// Requiring all the necessary dependencies
const express = require('express')
const app = express()
const bcrpyt = require('bcrypt')
const users = []
// In order to use ejs set up view-engine
app.set('view-engine', 'ejs')
app.use(express.urlencoded({ extended: false }))
// Setting up home-page route
app.get('/', (req, res) => {
res.render('index.ejs', { name: 'Janhvi' })
})
// Set up login page route
app.get('/login', (req, res) => {
res.render('login.ejs')
})
// Set up register page route
app.get('/register', (req, res) => {
res.render('register.ejs')
})
app.post('/register', async (req, res) => {
// Using try catch block in order to
// resolve errors
try {
// Hashing password with bcrypt
const hashedPassword =
await bcrpyt.hash(req.body.password, 10)
users.push({
id: Date.now().toString(),
name: req.body.name,
email: req.body.email,
password: hashedPassword
})
res.redirect('/login')
} catch {
res.redirect('/register')
}
console.log(users)
})
// To run our app on port 3000
app.listen(3000)
login.ejs
JavaScript
<!-- login page -->
<h1>Login</h1>
<!-- Make a simple login form with name, email
and password fields make a submit button
at end -->
<form action="/login" 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">Login</button>
</form>
<a href="/register">Register</a>
register.ejs
JavaScript
<!-- Register page -->
<h1>Register</h1>
<!-- Make a simple register form with
name, email and password fields
make a submit button at end -->
<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>
Desired output on, http://localhost:3000/login

from login.ejs
http://localhost:3000/register

from register.ejs
Upon giving an input, the console will look like this with a hashed password

terminal
5: Install passportjs using “npm i passport passport-local express-session express-flash”
Make a file “passport-config.js” in which you will store all the passport-related information. Now let’s have a look at the final version of all the codes with desired logic.
server.js
JavaScript
// The below code is only suitable for
// development not suitable for production
if (process.env.NODE_ENV !== 'production') {
require('dotenv').config()
}
// Requiring all the necessary dependencies
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')
const initializePassport = require('./passport-config')
initializePassport(
passport,
email => users.find(user => user.email === email),
id => users.find(user => user.id === id)
)
const users = []
// Setting up the view-engine in order
// to use ejs in code further
app.set('view-engine', 'ejs')
app.use(express.urlencoded({ extended: false }))
app.use(flash())
app.use(session({
secret: process.env.SESSION_SECRET,
resave: false,
saveUninitialized: false
}))
app.use(passport.initialize())
app.use(passport.session())
app.use(methodOverride('_method'))
// Setting up route logic for home page
app.get('/', checkAuthenticated, (req, res) => {
res.render('index.ejs', { name: req.user.name })
})
// Setting up route logic for login page
app.get('/login', checkNotAuthenticated, (req, res) => {
res.render('login.ejs')
})
app.post('/login', checkNotAuthenticated,
passport.authenticate('local', {
successRedirect: '/',
failureRedirect: '/login',
failureFlash: true
}))
app.get('/register', checkNotAuthenticated,
(req, res) => {
res.render('register.ejs')
})
// Hashinhg the passwords for each user
// using bcrypt
app.post('/register', checkNotAuthenticated,
async (req, res) => {
try {
const hashedPassword =
await bcrypt.hash(req.body.password, 10)
users.push({
id: Date.now().toString(),
name: req.body.name,
email: req.body.email,
password: hashedPassword
})
res.redirect('/login')
} catch {
res.redirect('/register')
}
})
// To to login page upon pressing the
// logout button
app.delete('/logout', (req, res) => {
req.logOut()
res.redirect('/login')
})
// If user is authenticated redirect to
// next page otherwise redirect to login
// page
function checkAuthenticated(req, res, next) {
if (req.isAuthenticated()) {
return next()
}
res.redirect('/login')
}
function checkNotAuthenticated(req, res, next) {
if (req.isAuthenticated()) {
return res.redirect('/')
}
next()
}
// To run our app on port 3000
app.listen(3000)
passport-config.js
JavaScript
// Requiring all the necessary dependencies
const LocalStrategy = require('passport-local').Strategy
const bcrypt = require('bcrypt')
// Add all the code related to passportjs to
// the main initialize function
function initialize(passport, getUserByEmail, getUserById) {
const authenticateUser = async (email, password, done) => {
const user = getUserByEmail(email)
// If user is null return output
// "no user with that email"
if (user == null) {
return done(null, false,
{ message: 'No user with that email' })
}
// try-catch block to check for correct password
try {
if (await bcrypt.compare(password, user.password)) {
return done(null, user)
} else {
return done(null, false,
{ message: 'Password incorrect' })
}
} 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))
})
}
// Exporting the initialize function
module.exports = initialize
index.ejs
HTML
<!-- Index page which will display
the Hi user_name -->
<h1>Hi <%= name %></h1>
<!-- Setting up a logout button in
order to exit the page -->
<form action="/logout?_method=DELETE" method="POST">
<button type="submit">Log Out</button>
</form>
login.ejs
HTML
<!-- login page -->
<h1>Login</h1>
<!-- Adding embedded javascript code to
check for errors -->
<% if (messages.error) { %>
<%= messages.error %>
<% } %>
<!-- Make a simple login form with
name, email and password fields
make a submit button at the end -->
<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">Register</a>
register.ejs
HTML
<!-- Register page -->
<h1>Register</h1>
<!-- Make a simple register form with
name, email and password fields
make a submit button at the end -->
<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>
6: Install another package using “npm i method-override” – The rest of the code remains the same.
The first page that will come up after starting the server is the login page.

Â
If you have already registered, then login by using the same email and password.

Â
If you haven’t registered and you tried to login then you will get this output.

Â
Register yourself first and remember the email and password and then again try to login.

Â
After successful registration and login you will get this on your page i.e. “Welcome to GeeksforGeeks your_name”.

Â
Â
Output:
Similar Reads
How to use SSL/TLS with Node.js ?
TLS/SSL is used for establishing secure connections over the internet. Today, most websites use HTTPS to communicate with clients. HTTPS is basically HTTP running over TLS/SSL. Web clients like browsers alert users about websites that do not use HTTPS since such websites are vulnerable to cyber-atta
5 min read
How to Implement Visitor Counter in Node.js ?
Implementing a visitor counter in Node.js can be a useful feature for many web applications. It allows you to track the number of visits or hits a particular page or your entire website receives. In this article, weâll guide you through creating a simple visitor counter using Node.js and Express. We
4 min read
How to Reset / Change Password in Node.js with Passport.js ?
Resetting or changing passwords securely in Node.js applications using Passport.js typically involves a combination of strategies, including token generation, email communication, and password hashing. Let's go through the steps required to implement password reset functionality using these tools. S
5 min read
How to read and write JSON file using Node ?
Node JS is a free and versatile runtime environment that allows the execution of JavaScript code outside of web browsers. It finds extensive usage in creating APIs and microservices, catering to the needs of both small startups and large enterprises. JSON(JavaScript Object Notation) is a simple and
3 min read
How to use Routes with serve-static Files in Node.js ?
Using serve-static files with routes in a Node.js application involves creating a server with Express, defining routes, and serving static files like HTML, CSS, JavaScript, images, etc. Hereâs an article explaining how to use serve-static with routes in Node.js. Serving Static Files with Routes in N
3 min read
Google Authentication using Passport in Node.js
The following approach covers how to authenticate with google using passport in nodeJs. Authentication is basically the verification of users before granting them access to the website or services. Authentication which is done using a Google account is called Google Authentication. We can do Google
2 min read
How to Build Library Management System Using NodeJS?
A Library Management System is an essential application for managing books, users, and transactions in a library. It involves adding, removing, updating, and viewing books and managing users. In this article, we will walk through how to build a simple Library Management System using NodeJS. What We
6 min read
How to Build User Management System Using NodeJS?
A User Management System is an essential application for handling user accounts and information. It involves creating, reading, updating, and deleting user accounts, also known as CRUD operations. In this article, we will walk through how to build a simple User Management System using NodeJS. What W
6 min read
Node.js Securing Apps with Helmet.js
Helmet.js is a Node.js module that helps in securing HTTP headers. It is implemented in express applications. Therefore, we can say that helmet.js helps in securing express applications. It sets up various HTTP headers to prevent attacks like Cross-Site-Scripting(XSS), clickjacking, etc. Why securit
4 min read
How to write code using module.exports in Node.js ?
module is a discrete program, contained in a single file in Node.js. They are tied to files with one module per file. module.exports is an object that the current module returns when it is "required" in another program or module. We are going to see a simple code like the calculator to learn how to
3 min read