Hello. In this tutorial, we will create a simple node js application and implement an otp authentication login mechanism. Once the otp will be verified an access token will be generated that can be further used to access the secure api’s.
1. Introduction
Authentication and authorization are the key features of any application. Authentication provides access while authorization specifies what a user can do.
1.1 Setting up Node.js
To set upNode.js on windows you will need to download the installer fromthis 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.
1.2 Setting up Docker
If you already have the Docker running on your local machine you can ignore this step or if someone needs to go through the Docker installation, please watchthis video.
2. Otp authentication in nodejs
To set up the application, we will need to navigate to a path where our project will reside and I will be usingVisual Studio Code as my preferred IDE. Let a take a quick peek at the project structure.
2.1 Setting up related dependencies
2.1.1 Setting up Docker containers
docker-compose is a tool for running the docker applications in multiple containers. . In the project’ssetup directory present at the root level create a file nameddocker-compose.yml and paste the below code into it. We will set up the mongodb and mongo-express on localhost. Mongo-express is a visualization tool for mongodb. You’re free to change the configuration as your needs.
docker-compose.yml
services: mongodb: container_name: mongodb image: mongo environment: MONGO_INITDB_DATABASE: authentication # should match the db name used in the endpoint given in the default.json ports: - '27017:27017' express: container_name: express_1 image: mongo-express ports: - '9001:8081' environment: - ME_CONFIG_MONGODB_SERVER=mongodb - ME_CONFIG_MONGODB_PORT=27017 - ME_CONFIG_MONGODB_ENABLE_ADMIN=true depends_on: - mongodbversion: '3'
2.1.2 Setting up project packages
Navigate to the project directory and runnpm init -y to create apackage.json file. Thisfile holds the metadata relevant to the project and is used for managing the project dependencies, script, version, etc. Replace the generated file with the code given below –
package.json
{ "name": "otplogin", "version": "1.0.0", "description": "Otp-based authentication mechanism", "main": "index.js", "scripts": { "container-up": "docker-compose -f setup/docker-compose.yml up -d", "container-down": "docker-compose -f setup/docker-compose.yml down", "dev": "nodemon index.js", "start": "node index.js", "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [], "author": "javacodegeeks", "license": "MIT", "dependencies": { "bcrypt": "^5.0.1", "config": "^3.3.7", "express": "^4.18.1", "jsonwebtoken": "^8.5.1", "mongoose": "^6.4.7" }, "devDependencies": { "nodemon": "^2.0.19" }}Once the file is replaced trigger the belownpm command in the terminal window to download the different packages required for this tutorial. The downloaded packages will reside inside thenode_modules folder.
Downloading dependencies
npm install
2.2 Setting up code
2.2.1 Setting up the configuration file
Create a configuration file in theconfig folder that will hold the mongodb and application details.
default.json
{ "app": { "dev": { "endpoint": "mongodb://localhost:27017/authentication", "app_port": 3100, "tkn_secret_key": "8unto0n4oc7903zm" } }}2.2.2 Create a User model
Create a schema file representing the user model. This schema will be created in the mongo database named –authentication and will hold user-related information. The file also contains a method responsible to generate the jwt token once the otp is verified. The generated token can further be used to access the application’s secure api’s.
usr.js
const config = require("config");const { Schema, model } = require("mongoose");const jwt = require("jsonwebtoken");// user schemaconst usrSch = Schema( { number: { type: String, required: true } }, { timestamps: true });usrSch.methods.generateTkn = function () { return jwt.sign( { _id: this._id, number: this.number, issuer: "jcg" }, config.get("app.dev.tkn_secret_key"), { expiresIn: "1d" } );};module.exports.User = model("User", usrSch);2.2.3 Create an Otp authentication model
Create a schema file representing the otp model. This schema will be created in the mongo database named –authentication will hold the otp-related information for a given number. The schema is such that the otp record for a user will be auto removed after 5 minutes.
otp.js
const { Schema, model } = require("mongoose");// otp schemaconst otpSch = Schema( { number: { type: String, required: true }, otp: { type: String, required: true }, createdAt: { type: Date, default: Date.now, index: { expires: 300 } } }, { timestamps: true } // Auto remove after 5 minutes);module.exports.Otp = model("Otp", otpSch);2.2.4 Create a controller class
Create a controller file in thecontroller folder responsible to handle the requests from the user. The controller exposes 2 endpoints i.e./signup and/verify to generate and verify the otp for a number respectively.
/signup: Will persist the signup in the collection and generate the otp/verify: Will perform number and token validation. If pass generate the token to access secure api’s
ctrl.js
const bcrypt = require("bcrypt");const { User } = require("../model/usr");const { Otp } = require("../model/otp");const signUp = async (req, res) => { try { const input = req.body.number; // validating user let user = await User.findOne({ number: input }); if (user) return res.status(409).json({ info: "User already registered" }); // save user const usr = new User({ number: input }); await usr.save(); // generating otp let random = Math.floor(Math.random() * 90000) + 10000; console.log(random); // saving otp in db const otp = new Otp({ number: input, otp: random }); const salt = await bcrypt.genSalt(10); otp.otp = await bcrypt.hash(otp.otp, salt); const result = await otp.save(); console.log("saved", result); return res.status(201).json({ data: random, info: "Otp generated" }); } catch (err) { // console.log(err); return res.status(400).json({ info: err }); }};const verifyOtp = async (req, res) => { try { const input = req.body.number; const pwd = req.body.otp; if (pwd.length === 0) return res.status(400).json({ info: "Otp cannot be blank" }); // verifying user const otp = await Otp.find({ number: input }); if (!otp) return res.status(404).json({ info: "otp not found" }); // comparing otp const details = otp[otp.length - 1]; const valid = await bcrypt.compare(pwd, details.otp); if (input === details.number && valid) { // generating token const user = new User({ number: input }); const token = user.generateTkn(); // todo - save jwt tkn in db for comparison later // access_token for further usage like hitting secure api's etc - skipped for brevity for user to play return res .status(201) .json({ access_token: token, info: "Token generated" }); } else { return res.status(400).json({ info: "Bad request" }); } } catch (err) { // console.log(err); return res.status(400).json({ info: err }); }};module.exports = { signUp, verifyOtp};2.2.5 Create a router implementation
Create a routes file in therouter folder responsible to handle the routing from the user to the backend controller.
routes.js
const { signUp, verifyOtp } = require("../controller/ctrl");const express = require("express");const router = express.Router();///*-- http posthttp://localhost:3100/api/user/signup-- request body{ "number": "PHONE_NUMBER"}*/router.route("/signup").post(signUp);/*-- http posthttp://localhost:3100/api/user/verify-- request body{ "number": "PHONE_NUMBER", "otp": "OTP_GENERATED_VIA_SIGN_UP"}*/router.route("/verify").post(verifyOtp);module.exports = router;2.2.6 Create an implementation file
Create an implementation file in the project’s root directory responsible to handle the application startup and making a connection to the mongodb.
index.js
const config = require("config");const express = require("express");const mongoose = require("mongoose");const router = require("./router/routes");const app = express();app.use(express.json({ extended: false }));// exposing application routesapp.use("/api/user", router);// making a connection with mongodbmongoose .connect(config.get("app.dev.endpoint"), { useNewUrlParser: true, useUnifiedTopology: true }) .then(() => console.log("Successfully connected to mongo")) .catch((err) => console.log("Connection failed", err));// driver codeconst port = config.get("app.dev.app_port");app.listen(port, () => { console.log(`Application started at: http://localhost:${port}`);});3. Run the setup
3.1 Running the Docker containers
To run the containers I will be using thedocker-compose commands. Now you’re free to either execute thedocker-compose commands from the terminal window by first navigating to the path where thedocker-compose.yml file resides. You can download the file (cmds.txt) that contains the docker commands from theDownloads section. But we will run the containers with the help of the npm command as configured in thepackage.json file.
Run command
npm run container-up
Once this command is executed successfully the required containers will be downloaded and started up successfully. If everything goes well the container’s status can be verified with the help of thedocker ps -a command as shown below.
3.2 Running the node js application
To run the application navigate to the project directory and enter the following command as shown below in the terminal. The application will be started successfully on the port number –3100.
Run command
$ npm run start
Once the application is started successfully the logger message – “Successfully connected to mongo” will be shown on the terminal window. If the message – “Connection failed” is shown it means something is wrong with the application setup and you need to check the configuration.
4. Demo
The application exposes the below endpoints that you can explore around the application with the help of thepostman tool.
Application endpoints
// sign-up and generate otp/*-- http posthttp://localhost:3100/api/user/signup-- request body{ "number": "PHONE_NUMBER"}*/// verify otp and generate an access token/*-- http posthttp://localhost:3100/api/user/verify-- request body{ "number": "PHONE_NUMBER", "otp": "OTP_GENERATED_VIA_SIGN_UP"}*/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 how to set up the otp-based authentication in a nodejs application and persist the result in a mongo collection. You can download the source code from theDownloads section.
6. Download the Project
This was a tutorial to implement an otp authentication in a node js and express application.
You can download the full source code of this example here:otp authentication node js

Thank you!
We will contact you soon.








