In this article, I am going to explain about NodeJs Sms Verification system. We use NodeJs Sms Verification system to verify a users using their mobile number like Facebook, Google and LinkedIn does in order to get genuine users.
In this article, we will verify user’s mobile number by sending OTP on that mobile number and we will ask the user to enter that OTP which she/he received. Here, I will use Express for Nodejs,MongoDB to store user’s detail and at Client Side, we will use AngularJs.
1. How It Works
Before we start the development we need to understand how NodeJs Sms Verification system works.
NodeJs Sms Verification
- We will Store user’s information along with user’s mobile number.
- Whenever a user tries to verify her/his mobile number we will initiate a request to SMS Gateway to send an SMS with randomly generated OTP.
- SMS Gateway will deliver the SMS with OTP to user’s mobile number.
- Than OTP will be entered by user for verification and after verification, we will activate user’s mobile number
2. Signing up with SMS Gateway
To create NodeJs Sms Verification we have to buy one SMS Gateway. SMS gateways can send an SMS to any mobile number that comes under any mobile network. To send the SMS to a particular mobile number SMS gateways have a contract with all the mobile networks.
I did my research to find right SMS Gateway to deliver messages and I found Msg91, Solutions Infini, SMS Gupshupand Twilio are quite popular. But Unfortunately, none of them are free to Test.
However for this article, am using Msg91 as they have a flexible price range as well as very easy to integrate with the help of their node module.
1.So lets Sign-up to Msg91 in order to get API KEY
.
2.To send SMS, you have to buy some credits from Msg91. Go to this Linkand Click on buy creditsafter that you will be asked to fill a form.
3. In that form select SMS Type asTRANSACTIONAL ROUTEand give no.of SMS as 2500 which is minimum credits to buy. The cost would be around₹715 ,including service tax etc.
4.Now click next button you will be asked to fill a form where you have to provide your personal details. You will be redirected to Payment option once you click proceed after filling the form.
5.Proceed with the payment. Once the payment was done, you can see the SMS credits credited to your account.
6.To obtain your API key, goto the API doc and click on KEY on the top right corner. You will be shown your API Key in a popup dialog.
3. Creating NodeJs Sms Verification system
3.1 Getting started with mongoDB.
I am using MongoDB here and I assume the reader is pro-efficient in mongoDB. However, we don’t have any restriction to use mongoDB only you can use any Database of your choice.
Here, we have created a collection named as smsVerify(in the language of MySql I have a table). Where we will insert user details. We will fetch user’s mobile from the stored details and send SMS accordingly.
Below is the example of JSON we will store in our collection.
{ "_id" : ObjectId("574789f681d3144c15c57629"), "username" : "Shashank", "email" : "shashak@codershood.info", "password" : "rock", "mobile" : "**********", "isVerified" : true }
3.2 Creating New Nodejs Project
1. Till now we are ready with our SMS Gateways and MongoDB now it’s time to create nodejs project. Below is our folder structure for this project.
+--- middleware | +-- config.js | +-- db.js | +-- helper.js | +---routes.js | +--- node_modules | \ body-parser | \ ejs | \ express | \ express-session | \ msg91 | +--- views |\ css || |+-- bootstrap.min.css |+-- style.css |\ js || |+-- angular.min.js |+-- angular-route.js |+-- script.js (Script for Login & Registration Page) |\ pages || |+-- login.html |+-- home.html | |+-- index.html | +---server.js +---package.json
Folder structure
2. Now let’s start by running npm init
command in CMD to generate package.json file. Below is our package.json file.
package.json:
{ "name": "NodeJs-Sms-Verification-system-codershood", "version": "0.0.1", "description": "NodeJs-Sms-Verification-system-codershood", "author": "Shashank Tiwari", "license": "MIT", "dependencies": { "body-parser": "^1.15.0", "ejs": "^2.4.1", "express": "^4.13.4", "express-session": "^1.13.0", "mongodb": "^2.1.21", "msg91": "0.0.6", } }
3.2 Creating New Nodejs Files
1.Create a folder named as middleware
inside root directory this folder contains files which take care our routes, configuration, and Database connection.
2.Create a file named as config.js
inside middleware
folder. This file will take of express related configuration.
config.js:
var express = require("express"); var path= require('path'); var method=config.prototype; function config(app){ // Setting .html as the default template extension app.set('view engine', 'html'); // Initializing the ejs template engine app.engine('html', require('ejs').renderFile); // Telling express where it can find the templates app.set('views', (__dirname + '/../views')); //Files app.use(express.static(path.join('views'))); } method.get_config=function(){ return this; } module.exports = config;
3.Create a file db.js
inside middleware
folder. This file takes care of database connection.
db.js:
"use strict"; /*requiring mongodb node modules */const mongodb=require('mongodb'); const MongoClient = mongodb.MongoClient; const ObjectID = mongodb.ObjectID; const assert = require('assert'); const MongoUrl='mongodb://localhost:27017/nodeSms'; module.exports.onConnect = function(callback){ MongoClient.connect(MongoUrl, function(err, db) { assert.equal(null, err); callback(db,ObjectID); }); }
4. Now create a file called server.js. which needs no introduction I believe .
server.js:
/*requiring node modules starts */var app = require("express")(); var http = require('http').Server(app); /*requiring node modules ends */ /* requiring config file starts*/require('./middleware/config.js')(app); /* requiring config file ends*/ /* requiring config db.js file starts*/require("./middleware/db.js"); /* requiring config db.js file ends*/ /* requiring config db.js file starts. This files handles the all the Routes for this application. */require('./middleware/routes.js')(app); http.listen(81,function(){ console.log("Listening on http://127.0.0.1:81"); });
5.Now create a file named as helper.js
inside middleware
folder. This file contains Core Logic and all the major functions to perform the read, write operations onto the database.
helper.js:
'use strict'; const Mongodb = require("./db"); const MSG91 = require("./MSG91"); const self={ createUser:function(data,callback){ var response={}; const userInfo={ "email" : data.email }; Mongodb.onConnect(function(db,ObjectID){ db.collection('smsVerify').findOne(data,function(err, result){ if(err){ response.process = false; response.isUserExists = false; response.message = "Something went Wrong,try after sometime."; }else{ if(result != null ){ response.process = true; response.isUserExists = true; response.message = "User already exists."; callback(response); }else{ db.collection('smsVerify').insertOne(data,function(err, result) { if(err){ response.process = false; response.isUserExists = false; response.isUserAdded = false; response.message = "Something went Wrong,try after sometime."; }else{ response.process = true; response.isUserExists = false; response.isUserAdded = true; response.id=result.ops[0]._id; response.message = "User added."; } callback(response); }); } } }); }); }, isUserExists:function(data,callback){ var response={}; Mongodb.onConnect(function(db,ObjectID){ db.collection('smsVerify').findOne(data,function(err, result){ if(result != null ){ response.process = "success"; response.isUserExists = true; response.id = result._id; }else{ response.process = "failed"; response.isUserExists = false; } callback(response); }); }); }, getUserInfo:function(data,callback){ var response={}; Mongodb.onConnect(function(db,ObjectID){ data._id = new ObjectID(data._id); db.collection('smsVerify').findOne(data,function(err, result){ if(result != null ){ response.process = "success"; result.mobile = (result.mobile).substr((result.mobile).length-4); response.data = { username : result.username, isVerified : result.isVerified, mobile : result.mobile, email : result.email }; }else{ response.process = "failed"; response.isUserExists = false; } callback(response); }); }); }, sendOtp:function(data,callback){ console.log(data); var OTP = self.generateOtp(); var response={}; Mongodb.onConnect(function(db,ObjectID){ data._id = new ObjectID(data._id); db.collection('smsVerify').findOne(data,function(err, result){ console.log(result.mobile); if(result != null ){ if(result.mobile == "" || result.mobile == null){ response.process = false; response.message = "Invalid Number"; callback(response); }else{ MSG91.sendSms(OTP,result.mobile,function(err,result){ if(err){ response.process = false; response.otpCreated = "Something went Wrong Please try after sometime."; }else{ response.process = true; response.message = "Your OTP is Created."; response.otp = OTP; } console.log(response); callback(response); }); } }else{ response.process = false; response.message = "Invalid Number"; callback(response); } }); }); }, verifyOtp:function(data,otpData,callback){ const sessionOtp = parseInt(otpData.otp); const sessionUserID = otpData.id; const UserOtp = parseInt(data.otp); const userID = data.id; var response={}; if(UserOtp == "" || typeof UserOtp == "" || UserOtp == null){ response.isVerified=false; response.message="OTP is destroyed,Please resend OTP."; callback(response); }else{ if(UserOtp === sessionOtp){ self.activateVerification(userID,function(result){ if(result.isError){ response.isVerified=true; response.message="Something went Wrong at our end."; }else{ response.isVerified=true; response.message="Your Number is Verified"; } callback(response); }); }else{ response.isVerified=false; response.message="OTP does not match."; callback(response); } } }, activateVerification:function(userID,callback){ var response={}; Mongodb.onConnect(function(db,ObjectID){ db.collection('smsVerify').updateOne( { _id: new ObjectID(userID) }, { $set: {isVerified: true} },function(err, results) { if(err){ console.log(err); response.isError=true; response.isVerified=false; callback(response); }else{ console.log(results.result.nModified); if(results.result.nModified > 0){ response.isError=false; response.isVerified=true; }else{ response.isError=true; response.isVerified=false; } callback(response); } } ); }); }, generateOtp:function(){ return Math.floor(Math.random() * 10000) + 9999; } } module.exports = self;
6. Create one more file named as MSG91.js which contains a function to send messages to different numbers.
MSG91.js:
'use strict'; /* msg91 constants starts */ const API_KEY = '{{API_KEY}}'; const SENDER_ID = "VERIFY"; const ROUTE_NO = 4; /* msg91 constants starts */ var msg91 = require("msg91")(API_KEY, SENDER_ID, ROUTE_NO ); const self={ sendSms : function(OTP,mobileNo,callback){ var MESSAGE = "Welcome to codershood.info. your OTP is "+OTP; msg91.send(mobileNo, MESSAGE, function(err, response){ callback(err,response); }); } } module.exports = self;
6.Till now we have our core logic ready. Now we have to create front end files and we have to manage our routes. Now let’s create a routes.js file inside the middleware folder.
List of routes:
1. /login
: As the name justifies itself.
2. /register
: We use this routes for user Registration.
3. /getUserInfo
: To fetch the information based on mongoDB document ID.
4. /sendOtp
: Here we are sending SMS to given mobile number.
5. /verifyOtp
: Here we are verifying the OTP by comparing user’s OTP with OTP stored in the session.
6. /logout
: this method will logs out users from our application
what is happening in below code:
1.When the user enters OTP and clicks the verify button the OTP will be received in /verifyOtp
as a POST param.
2. then user’s OTP will be compared against OTP stored in the session.
3.If OTP matches we will update the status of isVerified field by updating the Document.
routes.js:
const bodyParser = require('body-parser'); var Session = require('express-session'); var Session= Session({ secret:'secrettokenhere', saveUninitialized: true, resave: true, cookie:{maxAge:50000} }); // requiring Helper file to run helper functions const helper = require('./helper'); var method=routes.prototype; function routes(app){ app.use(bodyParser.json()); app.use(Session); var sessionInfo; app.get('/', function(req, res){ res.render('index'); }); app.post('/login', function(req, res){ sessionInfo = req.session; const data={ "email" : req.body.email, "password" : req.body.password } helper.isUserExists(data,function(result){ if(result.isUserExists === true){ sessionInfo.sessionData = { userID:result.id }; } res.writeHead(200, {'Content-Type': 'text/plain'}); res.end(JSON.stringify(result)); }); }); app.post('/register', function(req, res){ sessionInfo = req.session; const data={ username : req.body.name, email : req.body.email, password : req.body.password, mobile : req.body.mobile, isVerified :false } helper.createUser(data,function(result){ if(typeof result.isUserAdded != "undefined" && result.isUserAdded == true){ sessionInfo.sessionData = { userID:result.id }; } res.writeHead(200, {'Content-Type': 'text/plain'}); res.end(JSON.stringify(result)); }); }); app.post('/getUserInfo', function(req, res){ sessionInfo = req.session; if(typeof sessionInfo.sessionData == "undefined" || sessionInfo.sessionData == null){ res.writeHead(200, {'Content-Type': 'text/plain'}); res.end(JSON.stringify({process:"failed"})); }else{ if(sessionInfo.sessionData.userID == "" || sessionInfo.sessionData.userID != req.body.id){ res.writeHead(200, {'Content-Type': 'text/plain'}); res.end(JSON.stringify({process:"failed"})); }else{ const data={ _id : req.body.id }; helper.getUserInfo(data,function(result){ res.writeHead(200, {'Content-Type': 'text/plain'}); res.end(JSON.stringify(result)); }); } } }); app.post('/sendOtp', function(req, res){ sessionInfo = req.session; const userID=req.body.id; const data={ _id : userID } helper.sendOtp(data,function(result){ console.log(result); var response={}; if(result.process){ sessionInfo.otpData={ id : userID, otp : result.otp }; response.otpCreated = true; }else{ response.otpCreated = false; response.message = result.message; } response.message = result.message; res.writeHead(200, {'Content-Type': 'text/plain'}); res.end(JSON.stringify(response)); }); }); app.post('/verifyOtp', function(req, res){ sessionInfo = req.session; const data={ otp : req.body.otp, id : req.body.id } const otpData = sessionInfo.otpData; helper.verifyOtp(data,otpData,function(result){ res.writeHead(200, {'Content-Type': 'text/plain'}); res.end(JSON.stringify(result)); }); }); app.post('/logout', function(req, res){ sessionInfo = req.session; sessionInfo.sessionData = null; res.end(); }); app.get('/getBalance', function(req, res){ helper.getBalance(function(result){ res.writeHead(200, {'Content-Type': 'text/plain'}); res.end(JSON.stringify('Done')); }); }); } method.getroutes=function(){ return this; } module.exports = routes;
3.3 Creating Front End
Now our NodeJs server is ready, It’s time to create Front End Files. Here we are using angular.js and our application will be single page application.
So for that, I have created a new folder named as pages inside views folder. We have two files login.html and home.html inside pages folder.
But before that create a index.html out side of pages folder i.e. views folder.
index.html:
<html ng-app="home"> <head> <title>NodeJs Sms Verification system www.codershood.info</title> <link rel="stylesheet" href="css/bootstrap.min.css"> <link rel="stylesheet" href="css/style.css"> </head> <body ng-controller="home"> <div class="container"> <div ng-view></div> </div> <script type="text/javascript" src = "js/angular.min.js"></script> <script type="text/javascript" src = "js/angular-route.js"></script> <script type="text/javascript" src ="js/script.js"></script> </body> </html>
Now to perform Login and Registration we have created login.html. Below is code for login.html.
login.html:
<div class="row"> <div class="col-md-4 col-md-offset-1"> <h2>Login</h2> <div class="loginBox"> <label>Email : </label> <input type="text" class="form-control email-login" id="emailLogin" placeholder="Email" ng-model="emailLogin"> <br/> <label>Password : </label> <input type="text" class="form-control password-login" id="passwordLogin" placeholder="Password" ng-model="passwordLogin"> <br/> <button class="btn btn-primary" id="login" ng-click="login()">Login</button> </div> </div> <div class="col-md-5"> <h2>Register</h2> <div class="registerBox"> <label>Name : </label> <input type="text" class="form-control name-register" id="nameRegister" placeholder="Email" ng-model="nameRegister"> <br/> <label>Email : </label> <input type="text" class="form-control email-register" id="emailRegister" placeholder="Email" ng-model="emailRegister"> <br/> <label>Moble number : </label> <input type="text" class="form-control mobile-register" id="mobileRegister" placeholder="Mobile" ng-model="mobileRegister"> <br/> <label>Password : </label> <input type="text" class="form-control password-register" id="passwordRegister" placeholder="Password" ng-model="passwordRegister"> <br/> <button class="btn btn-primary" id="register" ng-click="register()">Register</button> </div> </div> </div>
Code for home.html where the user can verify his/her mobile number.
home.html:
<div class="container"> <header> <h2>Hello {{ username }}</h2> <a ng-click="logout()">logout</a> </header> <div class="information"> <h3>Your mobile number ******{{ mobile }} is {{ isVerified === true ? "Verified" : "not Verified"}}</h3> </div> <div id="otpSection" class="otpSection"> <div id="sendOtpSection" class="sendOtpSection"> <button class="btn btn-primary sendOtp" id="sendOtp" ng-click="sendOTP()">Send OTP</button> </div> <div id="verifyOtpSection" class="verifyOtpSection"> <input type="number" class="form-control" id="otp" placeholder="Enter OTP" ng-model="enteredOtp"> <br/> <button class="btn btn-primary verifyOtp" id="verifyOtp" ng-click="verifyOTP()">Verify OTP</button> </div> </div> </div>
As of now, we only have HTML file we have to write some AngularJs to make it useful. In below script we have two controllers one is for login page and other is for the home page. Below is the code for script.js and style.css.
script.js:
"use strict"; var app = angular.module('home',['ngRoute']); app.config(function($routeProvider) { $routeProvider // route for the Login page .when('/', { templateUrl : 'pages/login.html', controller : 'index' }) // route for the home page .when('/home', { templateUrl : 'pages/home.html', controller : 'home' }) }); /*--------------------------------------------------------------------------------- Making service to run ajax ---------------------------------------------------------------------------------*/app.service('runajax', ['$http', function ($http) { this.runajax_function = function(request,callback){ var url=request.url; var data=request.data; $http.post(url,data).success(function(data, status, headers, config) { callback(data); }) .error(function(err){ callback(err); }); } }]); app.controller('index', function ($scope,$window,runajax) { /*--------------------------------------------------------------------------------- Call to Login ---------------------------------------------------------------------------------*/ $scope.login = function() { if (typeof $scope.emailLogin == "undefined" || $scope.emailLogin == "" ) { alert(`Enter Login Email`); }else if(typeof $scope.passwordLogin == "undefined" || $scope.passwordLogin == "" ){ alert(`Enter Login Password`); }else{ var urlData={ url:'/login', data:{ email:$scope.emailLogin, password:$scope.passwordLogin } } runajax.runajax_function(urlData,function(userData){ if(userData.isUserExists){ $window.location.href ="/#/home?id="+userData.id; }else{ alert(`Not Done Login Failed`); } }); } }; /*--------------------------------------------------------------------------------- Call to Register ---------------------------------------------------------------------------------*/ $scope.register = function() { if (typeof $scope.nameRegister == "undefined" || $scope.nameRegister == "" ) { alert(`Enter Register Name`); }else if(typeof $scope.emailRegister == "undefined" || $scope.emailRegister == "" ){ alert(`Enter Register Email`); }else if(typeof $scope.passwordRegister == "undefined" || $scope.passwordRegister == "" ){ alert(`Enter Register Password`); }else if(typeof $scope.mobileRegister == "undefined" || $scope.mobileRegister == "" ){ alert(`Enter Register Mobile `); }else{ var urlData={ url:'/register', data:{ name:$scope.nameRegister, email:$scope.emailRegister, password:$scope.passwordRegister, mobile:$scope.mobileRegister } } runajax.runajax_function(urlData,function(userData){ console.log(userData); if(userData.process){ if(userData.isUserExists){ alert(userData.message); }else{ $window.location.href ="/#/home?id="+userData.id; } }else{ alert(userData.message); } }); } }; }); app.controller('home', function ($scope,$window,$routeParams,runajax) { $scope.username=""; $scope.mobile = ""; $scope.isVerified = ""; const userId= $routeParams.id; /*--------------------------------------------------------------------------------- Call to getUserInfo ( Getting user's info.) ---------------------------------------------------------------------------------*/ if(typeof $routeParams.id != "undefined"){ var urlData={ url:'/getUserInfo', data:{ id : userId } }; runajax.runajax_function(urlData,function(userData){ if(userData.process == "failed"){ $window.location.href ="/#/"; }else{ userData=userData.data; $scope.username = userData.username; $scope.mobile = userData.mobile; $scope.isVerified = userData.isVerified; if( userData.isVerified == false){ document.querySelector( '#sendOtpSection' ).style.display="block"; } } }); } /*--------------------------------------------------------------------------------- Call to sendOTP ( To send OTP.) ---------------------------------------------------------------------------------*/ $scope.sendOTP = function() { var urlData = { url:'/sendOtp', data:{ id : userId } }; runajax.runajax_function(urlData,function(result){ if(result.otpCreated === true){ document.querySelector( '#sendOtpSection' ).style.display="none"; document.querySelector( '#verifyOtpSection' ).style.display="block"; } alert(result.message); }); }; /*--------------------------------------------------------------------------------- Call to verifyOTP ( To verify OTP.) ---------------------------------------------------------------------------------*/ $scope.verifyOTP = function() { if(typeof $scope.enteredOtp == "undefined" || $scope.enteredOtp == ""){ alert(`Enter OTP`); }else{ var urlData = { url:'/verifyOtp', data:{ otp : $scope.enteredOtp, id : userId } }; runajax.runajax_function(urlData,function(result){ if(result.isVerified === true){ $scope.isVerified = true; document.querySelector( '#sendOtpSection' ).style.display="none"; document.querySelector( '#verifyOtpSection' ).style.display="none"; }else{ document.querySelector( '#verifyOtpSection' ).style.display="none"; document.querySelector( '#sendOtpSection' ).style.display="block"; } alert(result.message); }); } }; /*--------------------------------------------------------------------------------- Call to logout ( To logout user.) ---------------------------------------------------------------------------------*/ $scope.logout = function(){ var urlData = { url:'/logout', data:{ id : userId } }; runajax.runajax_function(urlData,function(result){ $window.location.href ="/#/"; }); } });
style.css:
.registerBox, .loginBox, .sendOtpSection, .verifyOtpSection{ padding: 20px 25px; } .sendOtpSection, .verifyOtpSection{ display: none; }
Further enhancement :
Well, this brings us to end of this NodeJs Sms Verification article and you can make some changes in the code as I have listed below.
- you can use Database to store OTP.
- you can make a restriction that the user is allowed to enter OTP within XYZ minutes (for eg 15 minutes).
I hope you like this article feel free to give your suggestion and thoughts in below.
thanks for sharing this article. i’m doing the same but the main problem is when i click on register it’s alerting undefined. And in console it showing POST http://localhost:50135/register 404 (Not Found)
Hii abhay,
Make sure have defined the ‘register’ route in routes.js file. Let me know if still not working !
Yeah I’ve defined . I’ve copy and paste your code also and follow your instruction
I would recommend you to download the code and try again.
i’ve downloaded how to i run
Open your project directory in CMD, and run ‘npm install’ to install the dependencies. Now check your project directory there must be a folder named as npm_modules.
Now to run the app use below command in CMD,
‘npm start’