Login Authentication using Express.js, Passport.js and BCrypt
Last Updated :
21 Sep, 2023
In this article, we will create a Login Authentication application. This application basically displays a login/register form interface and authenticate the user. All this logic of login/register authentication is implemented using express, mongodb, passport and bcrypt and frontend is created using ejs.
Preview of Final Output:
Prerequisites and Technologies:
Approach: Our project contains two sections server and client. In client we will take the user inputs such as the username, password and then use the form action property to sent to the server. After that, we will build the required API’s to call the authentication routes in server section. In the server section, we will use mongo express passport and bcrypt to make Authentication routes for client section we will use view engine ejs.
Steps to create the application: To create a login authentication we will work on Server Section first then Client section.
Creating the Server Section:
Step 1: Create a folder name LoginAuth using the following command:
mkdir LoginAuth
Step 2: Intialize package.json using the following command
npm init -y
Step 3: create a file in server.js using following command
touch ./server.js
Step 4: Install the required modules:
npm install ejs express mongoose passport passport-local bcrypt express-session cookie-parser body-parser
concurrently is used to run both the server aand client simultaneouly
Step 5: Create necessary server files controllers.js db.js models.js passp.js routes.js pages.js :
The updated dependencies in package.json will look like:
{
"name": "loginauth",
"version": "1.0.0",
"description": "",
"main": "server.js",
"scripts": {
"server": "nodemon run server.js",
},
"author": "",
"license": "ISC",
"dependencies": {
"bcrypt": "^5.1.0",
"body-parser": "^1.20.2",
"cookie-parser": "^1.4.6",
"ejs": "^3.1.9",
"express": "^4.18.2",
"express-session": "^1.17.3",
"mongoose": "^7.4.0",
"passport": "^0.6.0",
"passport-local": "^1.0.0"
}
}
Creating Client Section:
Step 1: In LoginAuth create a folder name views to store our ejs files
mkdir views
Step 2: Create necessary files for client:
cd views
Step 3: Inside this folder create files home.ejs register.ejs login.ejs
Step 3: Import Tailwind by addind this line in every ejs file:
<script src="https://cdn.tailwindcss.com"></script>
Project Structure:
Example: Write the following code in respective files in server and client section
Server section:
- server.js: main server files contains the code of everything This the base file that connects to the others files and connects at 3000 port:
- db.js: contains the logic of database connections to the MongoDB.
- passp.js: contains the logic of user login authentication using passport-local module.
- controllers.js: contains the logic of register and logic route
- models.js: contains the models schema of our user collections.
- pages.js: contains the routes to pages of the website.
Javascript
const express = require( "express" );
const passport = require( "passport" );
const User = require( "./models.js" );
const localStrategy = require( "./passp.js" );
const controllers = require( "./controllers.js" );
const cookieParser = require( "cookie-parser" );
const connectDB = require( "./db" );
const ejs = require( "ejs" );
const bodyParser = require( "body-parser" );
const routes = require( "./pages.js" );
const session = require( "express-session" );
const app = express();
connectDB();
app.use(
session({
secret: "GFGLogin346" ,
resave: false ,
saveUninitialized: false ,
})
);
app.use(cookieParser());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(passport.initialize());
app.use(passport.session());
app.set( "view engine" , "ejs" );
passport.serializeUser((user, done) => done( null , user.id));
passport.deserializeUser((id, done) => {
User.findById(id, (err, user) => done(err, user));
});
app.use( "/api/" , controllers);
app.use( "/" , routes);
const port = 3000;
app.listen(port, () => {
console.log(`Server started on port ${port}`);
});
|
Javascript
const mongoose = require( "mongoose" );
const connectDB = async () => {
mongoose
useNewUrlParser: true ,
useUnifiedTopology: true ,
})
.then(() => console.log( "Connected to MongoDB" ))
. catch ((err) => console.error( "Error connecting to MongoDB:" , err));
};
module.exports = connectDB;
|
Javascript
const passport = require( "passport" );
const LocalStrategy = require( "passport-local" ).Strategy;
const User = require( "./models" );
const bcrypt = require( "bcrypt" );
passport.use(
new LocalStrategy(async (username, password, done) => {
try {
const user = await User.findOne({ username });
if (!user) {
return done( null , false , { error: "Incorrect username" });
}
const passwordsMatch = await bcrypt.compare(
password,
user.password
);
if (passwordsMatch) {
return done( null , user);
} else {
return done( null , false , { error: "Incorrect password" });
}
} catch (err) {
return done(err);
}
})
);
|
Javascript
const express = require( "express" );
const router = express.Router();
const User = require( "./models" );
const passport = require( "passport" );
const bcrypt = require( "bcrypt" );
router.post( "/register" , async (req, res) => {
console.log(req.body);
const { username, email, password, confirmpassword } = req.body;
if (!username && !email && !password && !confirmpassword) {
return res
.status(403)
.render( "register" , { error: "All Fields are required" });
}
if (confirmpassword !== password) {
return res
.status(403)
.render( "register" , { error: "Password do not match" });
}
try {
const existingUser = await User.findOne({ username });
if (existingUser) {
return res
.status(409)
.render( "register" , { error: "Username already exists" });
}
const salt = await bcrypt.genSalt(15);
const hashedPassword = await bcrypt.hash(password, salt);
const newUser = new User({ username, email, password: hashedPassword });
await newUser.save();
return res.redirect( "/login" );
} catch (err) {
return res.status(500).json({ message: err.message });
}
});
router.post(
"/login" ,
passport.authenticate( "local" , { session: false }),
(req, res) => {
req.session.name = req.body.username;
req.session.save();
return res.redirect( "/" );
}
);
router.get( "/logout" , (req, res) => {
req.session.destroy();
res.redirect( "/" );
});
module.exports = router;
|
Javascript
const mongoose = require( "mongoose" );
const userSchema = new mongoose.Schema({
email: { type: String, required: true , unique: true },
username: { type: String, required: true , unique: true },
password: { type: String, required: true },
});
const User = mongoose.model( "User" , userSchema);
module.exports = User;
|
Javascript
const express = require( "express" );
const router = express.Router();
router.get( "/" , (req, res) => {
if (req.session.name) {
var name = req.session.name;
res.render( "home" , { name: name });
}
return res.render( "home" , { name: null });
});
router.get( "/login" , (req, res) => {
if (req.session.name) {
res.redirect( "/" );
}
return res.render( "login" , { error: null });
});
router.get( "/register" , (req, res) => {
if (req.session.name) {
res.redirect( "/" );
}
return res.render( "register" , { error: null });
});
module.exports = router;
|
Client section:
- Home.ejs: Home of the project that will display if the user is logged in or not and give a message
- Register.ejs: Register Forms that will register the user in the database
- Login.ejs: Login Form that will authenticate and login the user
Javascript
<!-- Home.ejs -->
<!DOCTYPE html>
<html>
<head>
<title>Login Authentication</title>
</head>
<body>
<div class= "overflow-hidden h-screen p-8 bg-slate-200" >
<header class= "absolute inset-x-0 top-0 z-50" >
<nav class= "flex items-center p-6 lg:px-8"
aria-label= "Global" >
<div class= "flex lg:flex-1 text-blue-800 text-xl" >
<a className= " border-collapse text-blue-800 text-xl"
href= "/" >
Home
</a>
</div>
</nav>
</header>
<% if (name) { %>
<div class= "pt-10" >
<h1 class= "text-4xl font-bold tracking-tight
text-gray-900 sm:text-6xl" >
Welcome <%= name %>
</h1>
<p class= "mt-6 text-lg leading-8 text-gray-600" >
You 're Successfully Authenticated
</p>
<div class="mt-10 flex gap-x-6">
<a href="/api/logout"
class="rounded-md bg-indigo-600 px-3.5 py-2.5 text-sm
font-semibold text-white shadow-sm hover:bg-indigo-500
focus-visible:outline focus-visible:outline-2
focus-visible:outline-offset-2
focus-visible:outline-indigo-600">
Logout
</a>
</div>
<% } else { %>
<div class="pt-4 mt-2">
<h1 class="text-sm font-bold tracking-tight
text-gray-900 sm:text-6xl">
Invalid User
</h1>
<p class="mt-6 text-lg leading-8 text-gray-600">
You' re Not Authenticated please Login
</p>
<div class= "mt-10 flex gap-x-6" >
<a href= "/login"
class= "rounded-md bg-indigo-600 px-3.5 py-2.5 text-sm
font-semibold text-white shadow-sm
hover:bg-indigo-500 focus-visible:outline
focus-visible:outline-2 focus-visible:outline-offset-2
focus-visible:outline-indigo-600" >
Login
</a>
</div>
</div>
<% } %>
</div>
</div>
</body>
</html>
|
Javascript
<!--Login.ejs -->
<!DOCTYPE html>
<html lang= "en" >
<head>
<meta charset= "UTF-8" >
<meta name= "viewport"
content= "width=device-width, initial-scale=1.0" >
<title>Login Authentication</title>
</head>
<body>
<div class= "overflow-hidden h-screen p-8 bg-slate-200" >
<div class= "overflow-hidden h-screen " >
<header class= "absolute inset-x-0 top-0 z-50" >
<nav class= "flex items-center p-6 lg:px-8"
aria-label= "Global" >
<div class= "flex lg:flex-1 text-blue-800 text-xl ml-2 " >
<a className= " border-collapse text-blue-800 text-xl"
href= "/" >
Home
</a>
</div>
</nav>
</header>
<div class= "container py-8" >
<h1 class= "text-2xl font-bold ml-2 mb-4" >Login Form</h1>
<form class= "w-full max-w-sm bg-white
p-4 rounded-md shadow-md" method= "post" , action= "/api/login" >
<% if (error) { %>
<p class= "text-red-500" ><%= error %></p>
<% } %>
<div class= "mb-4" >
<label class= "block text-gray-700 text-sm font-bold mb-2"
for = "username" >
Username
</label>
<input class= "w-full px-3 py-2 border border-gray-300 rounded-md
focus:outline-none focus:border-indigo-500"
type= "text" id= "username" name= "username"
placeholder= "John_01" />
</div>
<div class= "mb-4" >
<label class= "block text-gray-700 text-sm font-bold mb-2"
for = "password" >
Password
</label>
<input class= "w-full px-3 py-2 border border-gray-300 rounded-md
focus:outline-none focus:border-indigo-500"
type= "password" id= "password" name= "password"
placeholder= "********" />
</div>
<button class= "w-full bg-indigo-500 text-white text-sm font-bold
py-2 px-4 rounded-md hover:bg-indigo-600
transition duration-300"
type= "submit" onClick={submit}>
Login
</button>
<p class= "pt-5" >
Don't have a account
<a class= " text-cyan-600 cursor-pointer" href= "/register" >
Register here
</a>
</p>
</form>
</div>
</div>
</body>
</html>
|
Javascript
<!-- Register.ejs -->
<!DOCTYPE html>
<html lang= "en" >
<head>
<meta charset= "UTF-8" >
<meta name= "viewport"
content= "width=device-width, initial-scale=1.0" >
<title>Login Authentication</title>
</head>
<body>
<div class= "overflow-hidden h-screen bg-slate-200 " >
<div class= "overflow-hidden h-screen " >
<header class= "absolute inset-x-0 top-0 z-50" >
<nav class= "flex items-center p-6 lg:px-8"
aria-label= "Global" >
<div class= "flex lg:flex-1 text-blue-800 text-xl " >
<a className= "border-collapse " href= "/" >
Home
</a>
</div>
</nav>
</header>
<div class= "container mt-8 p-8" >
<h1 class= "text-2xl font-bold mb-6 " >Registration Form</h1>
<form class= "w-full max-w-sm bg-white p-8
rounded-md shadow-md" method= "post" action= "/api/register" >
<% if (error) { %>
<p class= "text-red-500" ><%= error %></p>
<% } %>
<div class= "mb-4" >
<label class= "block text-gray-700
text-sm font-bold mb-2" for = "username" >
UserName
</label>
<input class= "w-full px-3 py-2 border border-gray-300 rounded-md
focus:outline-none focus:border-indigo-500"
type= "text" id= "username" name= "username"
placeholder= "John_01" />
</div>
<div class= "mb-4" >
<label class= "block text-gray-700 text-sm font-bold mb-2"
for = "email" >
Email
</label>
<input class= "w-full px-3 py-2 border border-gray-300 rounded-md
focus:outline-none focus:border-indigo-500"
type= "email" id= "email" name= "email"
placeholder= "john@example.com" />
</div>
<div class= "mb-4" >
<label class= "block text-gray-700 text-sm font-bold mb-2"
for = "password" >
Password
</label>
<input class= "w-full px-3 py-2 border border-gray-300 rounded-md
focus:outline-none focus:border-indigo-500"
type= "password" id= "password" name= "password"
placeholder= "********" />
</div>
<div class= "mb-4" >
<label class= "block text-gray-700 text-sm font-bold mb-2"
for = "confirm-password" >
Confirm Password
</label>
<input class= "w-full px-3 py-2 border border-gray-300 rounded-md
focus:outline-none focus:border-indigo-500"
type= "password" id= "confirm-password" name= "confirmpassword"
placeholder= "********" />
</div>
<button class= "w-full bg-indigo-500 text-white
text-sm font-bold py-2 px-4
rounded-md hover:bg-indigo-600
transition duration-300" type= "submit" onClick={submit}>
Register
</button>
<p class= "pt-5" >
Don't have a account
<a href= "/login" class= " text-cyan-600 cursor-pointer" >
Register here
</a>
</p>
</form>
</div>
</div>
</body>
</html>
|
Steps to run the application:
Step 1 : Start the mongodb server by typing the following command in terminal
mongod
Step 2: Inside the loginAuth folder.
npm run server
Step 3: Both the server and client will run simultaneously open the url
http://localhost:3000/
Output:
Project Database
Share your thoughts in the comments
Please Login to comment...