Building an OTP Verification System with Node.js and MongoDB
Tags: webdev, javascript, beginners, programming
Published: 2024-02-14 07:30:00

In today's digital world, security is paramount, especially when it comes to user authentication. One-time passwords (OTPs) are widely used to verify user identities during online transactions, account logins, and more. In this blog, we'll explore how to implement an OTP verification system using Node.js, Express.js, and MongoDB.

**Understanding the Components**

Before diving into the implementation details, let's understand the various components of our OTP verification system:

1. **Express.js**: A fast, unopinionated, minimalist web framework for Node.js. We'll use Express.js to handle HTTP requests and responses.

2. **MongoDB**: A popular NoSQL database used for storing and retrieving OTP data.

3. **Nodemailer**: A module for Node.js applications that allows easy email sending.

4. **Randomstring**: A library to generate random strings, which we'll use to create OTPs.

**Project Structure Overview**

```
otp-verification-system/
│
├── controllers/
│   └── otpController.js
│
├── models/
│   └── otpModel.js
│
├── routes/
│   └── otpRoutes.js
│
├── utils/
│   └── sendEmails.js
│
├── index.js
│
├── .env
│
└── package.json
```

**Understanding the Project Structure**

1. **controllers/**: This directory contains the controller functions responsible for handling the business logic of our OTP verification system. In this case, `otpController.js` holds the logic for sending and verifying OTPs.

2. **models/**: Here, we define the data models for our MongoDB database. The `otpModel.js` file specifies the schema for storing OTPs.

3. **routes/**: This directory houses the route definitions for our Express.js application. The `otpRoutes.js` file specifies the endpoints for sending and verifying OTPs.

4. **utils/**: This directory contains utility functions used within our application. The `sendEmails.js` file handles email sending using Nodemailer.

5. **index.js**: This is the entry point of our application where we set up our Express server, configure middleware, connect to the MongoDB database, and define route handling.

6. **.env**: This file stores environment variables such as database credentials, SMTP configuration, and any other sensitive information. We use the `dotenv` package to load these variables into our application.

7. **package.json**: This file contains metadata about our project and lists the dependencies required for our application. It also includes scripts for running and testing our application.

**Environment Variables in .env**

```plaintext
PORT=3000
MONGODB_USER=username
MONGODB_PASSWORD=password
SMPT_HOST=smtp.example.com
SMPT_PORT=587
SMPT_MAIL=your_email@example.com
SMPT_APP_PASS=your_smtp_password
```

**Setting Up the Environment**

First, let's set up our development environment. Make sure you have Node.js and npm installed on your system. Then, create a new directory for your project and initialize it with npm:

```bash
mkdir otp-generator
cd otp-generator
npm init -y
```

Now, install the required dependencies:

```bash
npm install express cors body-parser mongoose nodemailer randomstring dotenv
```

**Implementing the OTP Verification System**

Now, let's implement the OTP verification system step by step.

**Database Setup**: We'll start by setting up our MongoDB database and defining the OTP schema.

```javascript
// models/otpModel.js
const mongoose = require('mongoose');

const otpSchema = new mongoose.Schema({
    email: { type: String, required: true },
    otp: { type: String, required: true },
});

const Otps = mongoose.model('otps', otpSchema);

module.exports = Otps;
```

**Creating Routes**: Next, we'll define the routes for sending and verifying OTPs.

```javascript
// routes/otpRoutes.js
const express = require('express');
const { sendOTP, verifyOTP } = require('../controllers/otpController');

const router = express.Router();

router.get('/sendOTP', sendOTP);
router.get('/verifyOTP', verifyOTP);

module.exports = router;
```

**Implementing Controller Logic**: Now, let's implement the logic for sending and verifying OTPs.

```javascript
// controllers/otpController.js
const Otps = require('../models/otpModel.js');
const randomstring = require('randomstring');
const sendEmail = require('../utils/sendEmails');

// Generate OTP
function generateOTP() {
    return randomstring.generate({
        length: 6,
        charset: 'numeric'
    });
}

// Send OTP to the provided email
exports.sendOTP = async (req, res, next) => {
    try {
        const { email } = req.query;
        const otp = generateOTP(); // Generate a 6-digit OTP
        const newOTP = new Otps({ email, otp });
        await newOTP.save();
        
        // Send OTP via email
        await sendEmail({
            to: email,
            subject: 'Your OTP',
            message: `<p>Your OTP is: <strong>${otp}</strong></p>`,
        });

        res.status(200).json({ success: true, message: 'OTP sent successfully' });
    } catch (error) {
        console.error('Error sending OTP:', error);
        res.status(500).json({ success: false, error: 'Internal server error' });
    }
};

// Verify OTP provided by the user
exports.verifyOTP = async (req, res, next) => {
    try {
        const { email, otp } = req.query;
        const existingOTP = await Otps.findOneAndDelete({ email, otp });
        
        if (existingOTP) {
            // OTP is valid
            res.status(200).json({ success: true, message: 'OTP verification successful' });
        } else {
            // OTP is invalid
            res.status(400).json({ success: false, error: 'Invalid OTP' });
        }
    } catch (error) {
        console.error('Error verifying OTP:', error);
        res.status(500).json({ success: false, error: 'Internal server error' });
    }
};
```

**Configuring Email Sending**: Finally, we'll configure Nodemailer to send emails containing the OTP.

```javascript
// utils/sendEmails.js
const nodeMailer = require("nodemailer");

const sendEmail = async (options) => {
    const transporter = nodeMailer.createTransport({
        host: process.env.SMPT_HOST,
        port: process.env.SMPT_PORT,
        secure: true, // Use SSL
        auth: {
            user: process.env.SMPT_MAIL,
            pass: process.env.SMPT_APP_PASS,
        },
        authMethod: 'LOGIN', // Specify the authentication method
    });

    const mailOptions = {
        from: process.env.SMPT_MAIL,
        to: options.to,
        subject: options.subject,
        html: options.message,
    };

    await transporter.sendMail(mailOptions);
};

module.exports = sendEmail;
```

**Setting Up Express Server**: Finally, we'll set up our Express server to listen to incoming requests.

```javascript
// index.js
const express = require("express");
const app = express();
const PORT = process.env.PORT || 3000;
const cors = require("cors");
const bodyParser = require("body-parser");
const mongoose = require('mongoose');

const otpRoutes = require('./routes/otpRoutes');

require("dotenv").config();

const dbUser = process.env.MONGODB_USER;
const dbPassword = process.env.MONGODB_PASSWORD;

mongoose
    .connect(
        `mongodb+srv://${dbUser}:${dbPassword}@cluster0.re3ha3x.mongodb.net/otp`,
        { useNewUrlParser: true, useUnifiedTopology: true } // Add these options for MongoDB connection
    )
    .then(() => {
        console.log("Connected to MongoDB database!");
    })
    .catch((error) => {
        console.error("Connection failed!", error); // Log the error for better debugging
    });

app.use(
    cors({
        origin: "*",
    })
);
app.use(bodyParser.json());
app.use(express.static("public"));
app.use(express.json());

app.use('/api', otpRoutes);

app.listen(PORT, () => {
    console.log(`Server started on port ${PORT}`);
});
```

**Conclusion**

Congratulations! You've successfully implemented an OTP verification system using Node.js, Express.js, and MongoDB. This system enhances the security of your application by adding an extra layer of authentication. Feel free to customize and extend this system to meet the specific requirements of your project.

## Exploring the Code

Visit the [GitHub repository](https://github.com/manthanank/otp-generator) to explore the code in detail.

---

Feel free to customize the blog according to your preferences and provide more details or explanations where needed.