In today's tutorial, I am going to show you how implement OTP (one-time-password) verification authentication using nodemailer module in node.js and express.

Prerequisites

  • Node.js
  • To Continue with this tutorial, you should have installed Node.js in your pc. If you are still not installed Node.js in your machine you can download it from here.

    Initialize project

    So, to begin with we need initialize the project by running below command

    1
    npm init -y

    On passing this your app will be initialized with package.json file.

    Install required dependencies

    Now we need install all the dependencies and packages which need to development of this project.

    1
    npm install express body-parser nodemailer express-handlebars nodemon
  • express : Allows to define routes based on HTTP methods and URLs.
  • body-parser : Use to handle HTTP post requests and extract the entire body portion of an incoming request stream and exposes it on req.body.
  • nodemailer : Use to send email from provided email address to provided email address.
  • express-handlebars : Templating engines for web applications.
  • nodemon : Use to automatically restarting of our node application when any changes occur in our app.
  • We have installed all the required dependencies for our application and now we can comtinuw with our coding part.

    Create basic server

    First, you need to create a file called app.js in your main directory and add below code in it to create basic server.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    const express=require('express');
    const bodyparser=require('body-parser');
    const nodemailer=require('nodemailer');
    const path=require('path');
    const exphbs=require('express-handlebars');

    const app=express();

    // view engine setup
    app.engine('handlebars',exphbs({ extname: "hbs", defaultLayout: false, layoutsDir: "views/ "}));
    app.set('view engine','handlebars');

    // body parser middleware
    app.use(bodyparser.urlencoded({extended : false}));
    app.use(bodyparser.json());

    //static folder
    app.use('/public',express.static(path.join(__dirname, 'public')));

    app.get('/',function(req,res){
    res.send("Node.js 2 way authnetication");
    });

    //defining port
    const PORT=process.env.PORT||3000;
    app.listen(PORT,()=>{
    console.log(`app is live at ${PORT}`);
    })

    Now we have finished with the coding part of basic server. We can run our application by running below command in your terminal

    1
    nodemon app.js

    Construct static and templating files

    Now our app is working so before developing the routes for sending otp, we need to construct our static and templating files, so first we will code the contact.handlebars which will only contain a basic html form which is to be filled by the user. Create a folder called views in your main directory and create a file called contact.handlebars in it. Then just paste the below code in it.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Sign-up form</title>
    <link href="//maxcdn.bootstrapcdn.com/bootstrap/4.1.1/css/bootstrap.min.css" rel="stylesheet" id="bootstrap-css">
    <script src="//maxcdn.bootstrapcdn.com/bootstrap/4.1.1/js/bootstrap.min.js"></script>
    <script src="//cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
    </head>
    <body>
    <div class="container register">
    <div class="d-flex justify-content-center">
    <div class="col-md-9 register-right">
    <div class="tab-content" id="myTabContent">
    <div class="tab-pane fade show active" id="home" role="tabpanel" aria-labelledby="home-tab">
    <h3 class="register-heading">SignUp Here</h3>
    <form method="POST" action="send">
    <div class="row register-form">
    <div class="col-md-6">
    <div class="form-group">
    <input type="text" class="form-control" placeholder="First Name *"
    name="firstname" required />
    </div>
    <div class="form-group">
    <input type="email" class="form-control" placeholder="Your Email *" name="email"
    required />
    </div>
    </div>
    <div class="col-md-6">
    <div class="form-group">
    <input type="text" class="form-control" placeholder="Last Name *"
    name="lastname" required />
    </div>
    <div class="form-group">
    <input type="text" class="form-control" placeholder="Enter Your Answer *"
    name="phone" required />
    </div>
    <input type="submit" class="btnRegister" value="Register" />
    </div>
    </form>
    </div>
    </div>
    </div>
    </div>
    </div>
    </body>
    </html>

    Create a file called otp.handlebars in views folder and paste below code

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Sign-up form</title>
    <link href="//maxcdn.bootstrapcdn.com/bootstrap/4.1.1/css/bootstrap.min.css" rel="stylesheet" id="bootstrap-css">
    <script src="//maxcdn.bootstrapcdn.com/bootstrap/4.1.1/js/bootstrap.min.js"></script>
    <script src="//cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
    </head>
    <body style="margin-top: 30px;">
    <div class="container register">
    <div class="d-flex justify-content-center">
    <div class="contact">
    {{msg}}
    <form method="POST" action="verify">
    <p>
    <label>Enter otp</label>
    <input type="text" name="otp" required>
    </p>
    <p class="full">
    <button type="submit">Submit</button>
    </p>
    </form>
    <br>
    <form method="POST" action="resend">
    <p class="full">
    <button type="submit">resend otp</button>
    </p>
    </form>
    </div>
    </div>
    </div>
    </body>
    </html>

    Now we have completed work of all the static files, so let’s do main coding in app.js file.

    Configure nodemailer

    First we need to define a global variable and transporter function for nodemailer:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    //static folder

    ...
    var email;

    let transporter = nodemailer.createTransport({
    host: "smtp.gmail.com",
    port: 465,
    secure: true,
    service : 'Gmail',

    auth: {
    user: 'Your email',
    pass: 'your password',
    }

    });
    ...

    //defining port

    In this transporter function, it contains info about the host and port no. of your email services. I am using gmail here. If you use any other mail sender service you can specify it’s configuration here.

    you need to allow permission for non-secure apps in your gmail setting for nodemailer to use your gmail account. you can give permission from here.

    Derfine route for main page

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    //static folder

    ...

    app.get('/',function(req,res){
    res.render('contact');
    });

    ...
    var email;

    let transporter = nodemailer.createTransport({

    ...

    It simply render contact.handlebars page to the localhost:3000/

    Generate OTP

    Let’s generate our OTP and will make it global as we have to use many times in different routes.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    var email;
    ...

    var otp = Math.random();
    otp = otp * 1000000;
    otp = parseInt(otp);
    console.log(otp);

    ...

    let transporter = nodemailer.createTransport({

    Define other routes

    Let’s define our send route that we will be called when user submit the contact form. To configure it paste below code under the tranporter function:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    app.post('/send', function (req, res) {
    email = req.body.email;

    // send mail with defined transport object
    var mailOptions = {
    to: req.body.email,
    subject: "Otp for registration is: ",
    html: "<h3>OTP for account verification is </h3>" + "<h1 style='font-weight:bold;'>" + otp + "</h1>" // html body
    };

    transporter.sendMail(mailOptions, (error, info) => {
    if (error) {
    return console.log(error);
    }
    console.log('Message sent: %s', info.messageId);
    console.log('Preview URL: %s', nodemailer.getTestMessageUrl(info));

    res.render('otp');
    });
    });

    Next route is for resend otp. Paste below code under the /send route:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    app.post('/resend', function (req, res) {
    var mailOptions = {
    to: email,
    subject: "Otp for registration is: ",
    html: "<h3>OTP for account verification is </h3>" + "<h1 style='font-weight:bold;'>" + otp + "</h1>" // html body
    };

    transporter.sendMail(mailOptions, (error, info) => {
    if (error) {
    return console.log(error);
    }
    console.log('Message sent: %s', info.messageId);
    console.log('Preview URL: %s', nodemailer.getTestMessageUrl(info));
    res.render('otp', { msg: "otp has been sent" });
    });

    });

    Now we need to define our last route /verify. Paste below code in between /send and /resend routes:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    app.post('/verify', function (req, res) {

    if (req.body.otp == otp) {
    res.send("You has been successfully registered");
    }
    else {
    res.render('otp', { msg: 'otp is incorrect' });
    }
    });

    Now out app.js file is completed and it’s looked like this.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    const express = require('express')
    const bodyparser = require('body-parser')
    const nodemailer = require('nodemailer')
    const path = require('path')
    const exphbs = require('express-handlebars')

    const app = express();

    //View Engine
    app.engine('handlebars', exphbs({ extname: "hbs", defaultLayout: false, layoutsDir: "views/ " }));
    app.set('view engine', 'handlebars');

    // body parser middleware
    app.use(bodyparser.urlencoded({ extended: false }));
    app.use(bodyparser.json());

    //static folder
    app.use('/public', express.static(path.join(__dirname, 'public')));

    app.get('/', function (req, res) {
    res.render('contact');
    });

    var email;

    var otp = Math.random();
    otp = otp * 1000000;
    otp = parseInt(otp);
    console.log(otp);

    let transporter = nodemailer.createTransport({
    host: "smtp.gmail.com",
    port: 465,
    secure: true,
    service: 'Gmail',

    auth: {
    user: '[email protected]',
    pass: 'testuser123',
    }

    });

    app.post('/send', function (req, res) {
    email = req.body.email;

    // send mail with defined transport object
    var mailOptions = {
    to: req.body.email,
    subject: "Otp for registration is: ",
    html: "<h3>OTP for account verification is </h3>" + "<h1 style='font-weight:bold;'>" + otp + "</h1>" // html body
    };

    transporter.sendMail(mailOptions, (error, info) => {
    if (error) {
    return console.log(error);
    }
    console.log('Message sent: %s', info.messageId);
    console.log('Preview URL: %s', nodemailer.getTestMessageUrl(info));

    res.render('otp');
    });
    });

    app.post('/verify', function (req, res) {

    if (req.body.otp == otp) {
    res.send("You has been successfully registered");
    }
    else {
    res.render('otp', { msg: 'otp is incorrect' });
    }
    });

    app.post('/resend', function (req, res) {
    var mailOptions = {
    to: email,
    subject: "Otp for registration is: ",
    html: "<h3>OTP for account verification is </h3>" + "<h1 style='font-weight:bold;'>" + otp + "</h1>" // html body
    };

    transporter.sendMail(mailOptions, (error, info) => {
    if (error) {
    return console.log(error);
    }
    console.log('Message sent: %s', info.messageId);
    console.log('Preview URL: %s', nodemailer.getTestMessageUrl(info));
    res.render('otp', { msg: "otp has been sent" });
    });

    });

    //defining port
    const PORT = process.env.PORT || 3000;
    app.listen(PORT, () => {
    console.log(`app is live at ${PORT}`);
    })

    Conclusion

    In this tutorial, we obtain how can we implement OTP (one-time-password) verification authentication using nodemailer module in node.js and express.. You can obtain complete source code for this tutorial from this GitHub repository.

    Happy Coding