Skip to content

AdnanTech

Programming tutorials

  • Python
  • PHP
    • Laravel
    • WordPress
  • Javascript
    • React JS
    • Node.js
    • Vue JS
  • Databases
    • MySQL
    • MongoDB
  • Mobile apps
    • Android
    • iOS
  • Tutorials
    • Ticketing system
    • Chat app
  • Blog
  • Projects
  • API
    • Social network API
  • Services
    • Hash Generator
    • World Clock
    • Word Counter
    • Currency Converter
    • Financial Ledger
    • Time Difference
    • Stopwatch & Timer
    • Google Maps
  • SAAS
    • Job Entry

Tag: http

JWT Authentication – Node JS and Mongo DB

Posted on July 27, 2021December 18, 2023 by adnanafzal565

This tutorial will discuss how you can create a JWT authentication system (Login, Registration, and Logout) using JSON Web Token in Node JS and Mongo DB. You can follow the video below if you prefer a video tutorial:

First, make sure you have downloaded and installed Node JS and Mongo DB. You can also download Mongo DB Compass to view the database.

Setup the Project

First, create an empty folder anywhere on your computer and open the command prompt in it. Once CMD is open inside the folder, run the following command:

npm install express express-formidable mongodb http bcrypt jsonwebtoken ejs

This command will install the following modules:

  • express: A framework used for better routing, middleware etc.
  • express-formidable: To get the values from AJAX.
  • mongodb: To interact with database.
  • http: To handle HTTP requests.
  • bcrypt: To encrypt and decrypt the password.
  • jsonwebtoken: To generate JSON Web Token used for authentication.
  • ejs: View engine to display HTML pages.

Now, create a file named “server.js” at the root of your folder. To start the server you can use the following command:

node server.js

But every time you made some changes in the server.js file, you have to run that command again. To prevent this, you can install the nodemon module using the following command:

npm install -g nodemon

Then you can use the following command to keep the server running:

nodemon server.js

Start the Server

Open your server.js file and write the following code in it:

// include express module
var express = require("express");

// create instance of express
var app = express();

// use express-formidable middleware
var formidable = require("express-formidable");
app.use(formidable());

// include mongodb module
var mongodb = require("mongodb");

// get mongodb client
var mongoClient = mongodb.MongoClient;

// get ObjectId, it is unique for each document
var ObjectId = mongodb.ObjectId;

// create http server from express instance
var http = require("http").createServer(app);

// include bcrypt module
var bcrypt = require("bcrypt");

// include jsonwebtoken module
var jwt = require("jsonwebtoken");

// random secret string
var accessTokenSecret = "myAccessTokenSecret1234567890";

// use public folder for css and js files
app.use(express.static(__dirname + "public"));

// use ejs engine to render html files
app.set("view engine", "ejs");

var mainURL = "http://localhost:3000";

// start the server at port 3000
http.listen(3000, function () {
	console.log("Server started.");

	// connect with mongodb
	mongoClient.connect("mongodb://localhost:27017", function (error, client) {

		// database name will be "jwt_authentication"
		var database = client.db("jwt_authentication");
		console.log("Database connected");

	});
});

This will include all the necessary modules and start the server at port 3000. The module used for JWT authentication is named jsonwebtoken. You can access it from your browser with the following link:

http://localhost:3000/

You will see an error because there isn’t any route for the home page. Open your CMD and you will see 2 messages:

  1. “Server started.”
  2. “Database connected”

If you open the Mongo DB Compass you will not see a database. Because database will be created only there is at least one collection in it. So our database will be created when there is at least one user in our database.

User Registration

Go to the following address in your browser:

http://localhost:3000/signup

First, we are going to create a route in our server.js right after the database is connected.

server.js

// route for signup requests
app.route("/signup")

	// get request accessed from browser
	.get(function (request, result) {
		// render signup.ejs file inside "views" folder
		result.render("signup");
	});

Now we need to create a folder named views at our root folder. Inside this folder, create a file named signup.ejs (note the extension). Also create 2 more files, header.ejs and footer.ejs.

header.ejs

<!-- menu items will be created using Javascript -->
<ul id="main-menu">
	
</ul>

<script>
	// variables used in all files
	var mainURL = "http://localhost:3000";
	var accessTokenKey = "accessToken";
	var user = null;
</script>

Leave the footer.ejs file empty for now.

signup.ejs

<%- include ("header") %>

<form method="POST" onsubmit="return doRegister(this);">

	<table>
		<tr>
			<th>Name</th>
			<td>
				<input type="text" name="name" required />
			</td>
		</tr>

		<tr>
			<th>Email</th>
			<td>
				<input type="email" name="email" required />
			</td>
		</tr>

		<tr>
			<th>Password</th>
			<td>
				<input type="password" name="password" required />
			</td>
		</tr>

		<tr>
			<td>
				<input type="submit" name="submit" value="Register" />
			</td>
		</tr>
	</table>

</form>

<%- include ("footer") %>
<script>
	function doRegister(form) {

		// disable the submit button and show "Loading..." text
		form.submit.setAttribute("disabled", "disabled");
		form.submit.value = "Loading...";

		// create AJAX object
		var ajax = new XMLHttpRequest();

		// 1. method is POST
		// 2. path where request will be sent
		// 3. request will be asynchronous
		ajax.open("POST", mainURL + "/signup", true);

		// called everytime status of request changes
		ajax.onreadystatechange = function () {

			// when response is received from server
			if (this.readyState == 4) {

				// if the request is OK
				if (this.status == 200) {

					// response received from server
					console.log(this.responseText);

					// enable the submit button
					form.submit.removeAttribute("disabled");
					form.submit.value = "Register";

					// convert the JSON string into Javascript object
					var response = JSON.parse(this.responseText);

					// display message
					alert(response.message);

					// if the user is created, then redirect to login
					if (response.status == "success") {
						window.location.href = "/login";
					}
				}

				// if there is an internal server error
				if (this.status == 500) {
					console.log(this.responseText);
				}
			}
		};

		// create form data object from form
		var formData = new FormData(form);

		// actually sending the AJAX request
		ajax.send(formData);

		// prevent the form from submitting
		return false;
	}
</script>

This will show a form with input fields for name, email and password. Now we need to create a POST route in our server.js. We will chain the POST route after our “/signup” GET route.

// route for signup requests
app.route("/signup")

	// get request accessed from browser
	.get(function (request, result) {
		// render signup.ejs file inside "views" folder
		result.render("signup");
	})

	// post request called from AJAX
	.post(async function (request, result) {

		// get values from signup form
		var name = request.fields.name;
		var email = request.fields.email;
		var password = request.fields.password;

		// check if email already exists
		var user = await database.collection("users").findOne({
			"email": email
		});

		if (user != null) {
			result.json({
				"status": "error",
				"message": "Email already exists."
			});
			return true;
		}

		// encrypt the password
		bcrypt.hash(password, 10, async function (error, hash) {

			// insert in database
			await database.collection("users").insertOne({
				"name": name,
				"email": email,
				"password": hash,
				"accessToken": ""
			});

			// send the response back to client
			result.json({
				"status": "success",
				"message": "Signed up successfully. You can login now."
			});
		});
		
	});

If you run the code now, you will see a registration form. You can enter your name, email, and password and hit enter. The first time, you will see a success message and you will be redirected to the login route. You can refresh your Mongo DB Compass, and you will see your database and one collection of “users”. Inside this collection, you will see your document inserted. If you enter the same email again, you will get an error.

User Login – JWT authentication

Go to the following address in your browser:

http://localhost:3000/login

First, we are going to create a route in our server.js right after the signup route.

server.js

// route for login requests
app.route("/login")

	// get request accessed from browser
	.get(function (request, result) {

		// render login.ejs file inside "views" folder
		result.render("login");
	});

Then create a file named login.ejs and write the following code in it:

login.ejs

<%- include ("header") %>

<form method="POST" onsubmit="return doLogin(this);">
	<table>
		<tr>
			<th>Email</th>
			<td>
				<input type="email" name="email" required />
			</td>
		</tr>

		<tr>
			<th>Password</th>
			<td>
				<input type="password" name="password" required />
			</td>
		</tr>

		<tr>
			<td>
				<input type="submit" name="submit" value="Login" />
			</td>
		</tr>
	</table>
</form>

<%- include ("footer") %>
<script>
	function doLogin(form) {

		// disable the submit button and show "Loading..." text
		form.submit.setAttribute("disabled", "disabled");
		form.submit.value = "Loading...";

		// create AJAX object
		var ajax = new XMLHttpRequest();

		// 1. method is POST
		// 2. path where request will be sent
		// 3. request will be asynchronous
		ajax.open("POST", mainURL + "/login", true);

		// called everytime status of request changes
		ajax.onreadystatechange = function () {

			// when response is received from server
			if (this.readyState == 4) {

				// if the request is OK
				if (this.status == 200) {

					// response received from server
					console.log(this.responseText);

					// enable the submit button
					form.submit.removeAttribute("disabled");
					form.submit.value = "Login";

					// convert the JSON string into Javascript object
					var response = JSON.parse(this.responseText);

					// if user is logged in successfully
					if (response.status == "success") {

						// get access token from server
						var accessToken = response.accessToken;

						// save in local storage
						localStorage.setItem("accessToken", accessToken);

						// redirect to home page
						window.location.href = "/";
					} else {

						// display message
						alert(response.message);
					}
				}

				// if there is an internal server error
				if (this.status == 500) {
					console.log(this.responseText);
				}
			}
		};

		// create form data object from form
		var formData = new FormData(form);

		// actually sending the AJAX request
		ajax.send(formData);

		// prevent the form from submitting
		return false;
	}
</script>

This will show a form with input fields for email and password. Now we need to create a POST route in our server.js. We will chain the POST route after our “/login” GET route.

// route for login requests
app.route("/login")

	// get request accessed from browser
	.get(function (request, result) {

		// render login.ejs file inside "views" folder
		result.render("login");
	})

	// post request called from AJAX
	.post(async function (request, result) {

		// get values from login form
		var email = request.fields.email;
		var password = request.fields.password;

		// check if email exists
		var user = await database.collection("users").findOne({
			"email": email
		});

		if (user == null) {
			result.json({
				"status": "error",
				"message": "Email does not exists."
			});
			return false;
		}

		// check if password is correct
		bcrypt.compare(password, user.password, async function (error, isVerify) {
			if (isVerify) {

				// generate JWT of user
				var accessToken = jwt.sign({
					"email": email
				}, accessTokenSecret);

				// update JWT of user in database
				await database.collection("users").findOneAndUpdate({
					"email": email
				}, {
					$set: {
						"accessToken": accessToken
					}
				});

				result.json({
					"status": "success",
					"message": "Login successfully.",
					"accessToken": accessToken
				});

				return false;
			}

			result.json({
				"status": "error",
				"message": "Password is not correct."
			});
		});
	});

If you run the code now, you will see a login form. You can enter your email and password and hit enter. If the credentials are correct, then it will save the access token in your local storage in your browser, and you will be redirected to the home page. You can refresh your Mongo DB Compass, and you will see that the accessToken field of the user has been updated. If you enter the wrong credentials, then it will not update the database.

Home Page

Now we need to create a route for our home page in server.js:

// route for home page
app.get("/", function (request, result) {
	result.render("index");
});

Create a file named index.ejs inside views folder and write the following code in it:

<%- include ("header") %>

<%- include ("footer") %>

Now comes the footer part. Following will be the code of your footer.ejs file:

footer.ejs

<script>

	// get user on page load
	window.addEventListener("load", function () {
		getUser();
	});

	function getUser() {

		// check if user is logged in
		if (localStorage.getItem(accessTokenKey)) {

			// call AJAX to get user data
			var ajax = new XMLHttpRequest();
			ajax.open("POST", mainURL + "/getUser", true);

			ajax.onreadystatechange = function () {
				if (this.readyState == 4) {
					if (this.status == 200) {
						// console.log(this.responseText);

						var response = JSON.parse(this.responseText);
						if (response.status == "success") {
							// user is logged in
							window.user = response.user;
						} else {
							// user is logged out
							localStorage.removeItem(accessTokenKey);
						}

						showMainMenu();
					}

					if (this.status == 500) {
						console.log(this.responseText);
					}
				}
			};

			var formData = new FormData();
			formData.append("accessToken", localStorage.getItem(accessTokenKey));
			ajax.send(formData);

			return false;
		}

		showMainMenu();
	}

	function doLogout() {
		// send beacon to server before redirecting
		var formData = new FormData();
		formData.append("accessToken", localStorage.getItem(accessTokenKey));

		navigator.sendBeacon(mainURL + "/logout", formData);

		// remove access token from local storage
		localStorage.removeItem(accessTokenKey);
		return true;
	}

	function showMainMenu() {
		var html = "";

		// if user is logged in
		if (localStorage.getItem(accessTokenKey)) {
			html += `<li>
				<a href='/login' onclick='return doLogout();'>Logout</a>
			</li>`;
		} else {
			html += `<li>
				<a href='/login'>Login</a>
			</li>`;

			html += `<li>
				<a href='/signup'>Signup</a>
			</li>`;
		}

		// show in main menu
		document.getElementById("main-menu").innerHTML = html;
	}
</script>

This will show login and signup links if the user is not logged in. If the user is logged in, then it will display a logout button. When the logout button is clicked, it will be redirected to the “/login” route. But before redirecting, it will send a beacon to the server to empty the accessToken field in the database. So we need to create POST routes for “/getUser” and for “/logout”:

// return user data using access token
app.post("/getUser", async function (request, result) {
	var accessToken = request.fields.accessToken;

	var user = await database.collection("users").findOne({
		"accessToken": accessToken
	});

	if (user == null) {
		result.json({
			"status": "error",
			"message": "User has been logged out. Please login again."
		});
		return false;
	}

	result.json({
		"status": "success",
		"message": "Data has been fetched.",
		"user": user
	});
});

// empty the access token of user (logout)
app.post("/logout", async function (request, result) {
	var accessToken = request.fields.accessToken;

	await database.collection("users").findOneAndUpdate({
		"accessToken": accessToken
	}, {
		$set: {
			"accessToken": ""
		}
	});

	result.json({
		"status": "success",
		"message": "User has been logged out."
	});
});

With that, your authentication is completed. You can log in and log out now. Once you log out and refresh the Mongo DB Compass, you will see the accessToken field becomes empty. And it will again have the value once the user logged in again.

Why we used Beacon ?

You might have noticed that we have used Beacon instead of AJAX when the logout button is clicked. The reason for this is when the browser navigates from one page to another, the AJAX calls are sometimes aborted by the browser. To prevent this, we use beacons.

Get Data using AJAX

Now that your authentication system is done, you might want to show data to logged-in users only. So for example, you have a blogging website and you want to show your blog posts to logged-in users only. So you need to do the following steps.

1) Create Variable and a Function

In the file where you want to fetch and display the data, create the following variable and a function in Javascript.

<script>
    var onPostsPage = true;

    function getPosts() {
        // call ajax
    }
</script>

If you want to learn how to call an AJAX request and show data from it, follow this tutorial.

2) Call Function if Variable is Set

In your footer.ejs, when the user is logged-in, check if this variable is set and is true. If yes, then simply call that function.

// user is logged in
window.user = response.user;

if (typeof onPostsPage !== "undefined" && onPostsPage) {
    getPosts();
}

So, that’s how you can create a JWT authentication system In Node JS and Mongo DB.

Download the Code – JWT authentication

[wpdm_package id=’1265′]

Posted in MongoDB, Node.js Tagged bcrypt, ejs, express, formidable, http, jsonwebtoken, jwt, login authentication, mongo db, node js

Recent Posts

  • Show selected images from input type file – React
  • Add dynamic rows in React
  • Soft Delete 🗑 – Node.js, MongoDB
  • 2 ways to loop through a number in React
  • Get updated value from Child to Parent – React

Recent Comments

  1. canada pharmaceuticals online generic on PDF view in browser and export as file – PHP
  2. System on (no title)
  3. adnanafzal565 on (no title)
  4. adnanafzal565 on (no title)
  5. System on (no title)

Archives

  • May 2025
  • March 2025
  • February 2025
  • January 2025
  • November 2024
  • September 2024
  • August 2024
  • July 2024
  • June 2024
  • May 2024
  • April 2024
  • March 2024
  • February 2024
  • January 2024
  • November 2023
  • September 2023
  • August 2023
  • July 2023
  • June 2023
  • May 2023
  • April 2023
  • December 2022
  • November 2022
  • October 2022
  • September 2022
  • August 2022
  • July 2022
  • June 2022
  • May 2022
  • April 2022
  • March 2022
  • February 2022
  • January 2022
  • December 2021
  • November 2021
  • October 2021
  • September 2021
  • August 2021
  • July 2021
  • June 2021
  • May 2021
  • April 2021
  • March 2021
  • January 2021
  • December 2020
  • November 2020
  • October 2020
  • September 2020
  • August 2020
  • July 2020
  • June 2020

Categories

  • Android
  • Complete Projects
  • CSS
  • FFmpeg
  • Git
  • htaccess
  • HTML
  • iOS
  • Javascript
  • Laravel
  • Leap Motion Controller
  • MEVN
  • MongoDB
  • MySQL
  • Node.js
  • PHP
  • Python
  • React JS
  • Swift
  • Tips & Tricks
  • Uncategorized
  • Vue JS
  • WordPress
2019-2025
support@adnan-tech.com