Open In App

Multi Factor authentication using MERN

Last Updated : 05 Dec, 2023
Improve
Improve
Like Article
Like
Save
Share
Report

This article will guide you through creating a Multi-Factor Authentication (MFA) project using the MERN. This project aims to enhance security by implementing a multi-step authentication process. Users will be required to provide multiple forms of identification for access, adding an extra layer of protection.

Output Preview:

1

Output Preview

Prerequisites / Technologies Used:

Approach:

The project will include:

  • User login with MFA
  • Generation and validation of one-time passwords (OTPs)
  • Integration of OTP-based multi-factor authentication into the login process

Project Structure:

folder

Folder structure

package.json:

Frontend

"dependencies": {
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "react-scripts": "5.0.1",
    "web-vitals": "^2.1.4",
}

Backend

package.json:

"dependencies": {
    "body-parser": "^1.20.2",
    "cors": "^2.8.5",
    "express": "^4.18.2",
    "mongoose": "^7.6.5",
    "nodemailer": "^6.9.7",
    "randomatic": "^3.1.1",
  }

Steps to Create MERN Application:

Step 1: Create a new project directory:

mkdir mfa-mern
cd mfa-mern

Step 2: Initialize the project and set up the client and server directories:

npm init -y
mkdir client server

Step 3: Set Up the Backend (Node.js, Express.js, MongoDB)

cd server
npm init -y

Step 4: Install necessary dependencies:

npm install express mongoose nodemailer cors body-parser randomatic

Step 5: Set Up the Frontend (React)

cd ../client
npx create-react-app .

Step 6: Install necessary dependencies:

npm install react-router-dom

Step 7: Set Up MongoDB

Make sure you have MongoDB installed on your system. Start MongoDB and create a database named mfa-mern.

Implementation of Multi-Factor Authentication:

frontend:

Javascript




// client/src/components/Login.js
import React, { useState } from 'react';
import axios from 'axios';
import './Login.css';
 
const Login = () => {
    const [email, setEmail] = useState('');
    const [password, setPassword] = useState('');
    const [otp, setOtp] = useState('');
    const [showOtpField, setShowOtpField] = useState(false);
 
    const handleLogin = async () => {
        try {
            const response =
                await axios.post(
                    'http://localhost:3001/auth/login',
                    {
                        email,
                        password
                    }
                );
 
            if (response.data.success) {
                setShowOtpField(true);
                alert('OTP sent to your email. Check your inbox.');
            } else {
                alert(response.data.message);
            }
        } catch (error) {
            console.error('Error during login:', error.message);
            alert('An error occurred during login');
        }
    };
 
    const handleOtpVerification = async () => {
        try {
            const otpResponse =
                await
                    axios.post(
                        'http://localhost:3001/auth/verify-otp',
                        {
                            otp
                        }
                    );
 
            if (otpResponse.data.success) {
                alert('OTP Verified. User logged in.');
                // Redirect to your dashboard or perform any
                // additional actions for successful login
            } else {
                alert('Invalid OTP. Please try again.');
            }
        } catch (error) {
            console.error('Error during OTP verification:', error.message);
            alert('An error occurred during OTP verification');
        }
    };
 
    return (
        <div className="login-container">
            <input type="email"
                placeholder="Email"
                onChange={
                    (e) =>
                        setEmail(e.target.value)} />
            <input type="password"
                placeholder="Password"
                onChange={
                    (e) =>
                        setPassword(e.target.value)} />
 
            {showOtpField && (
                <>
                    <input type="text"
                        placeholder="OTP"
                        onChange={
                            (e) =>
                                setOtp(e.target.value)} />
                    <button className="login-button"
                        onClick={handleOtpVerification}>
                        Verify OTP
                    </button>
                </>
            )}
 
            <button className="login-button"
                onClick={handleLogin}>
                Login
            </button>
        </div>
    );
};
 
export default Login;


Javascript




// client/src/App.js
import React from 'react';
import Login from './components/Login';
 
function App() {
    return (
        <div className="App">
            <div style={centerStyle}>
                <h1>
                    MFA using
                    MERN Stack
                </h1>
            </div>
            <Login />
        </div>
    );
}
 
const centerStyle = {
    textAlign: 'center',
};
export default App;


Backend:

Javascript




const express = require('express');
const cors = require('cors');
const bodyParser = require('body-parser');
const mongoose = require('mongoose');
const nodemailer = require('nodemailer');
const randomize = require('randomatic');
 
const app = express();
const PORT = 3001;
 
app.use(bodyParser.json());
app.use(cors());
 
// Connect to MongoDB with connection pooling
    useNewUrlParser: true,
    useUnifiedTopology: true,
    // poolSize: 10,
});
 
const User = mongoose.model('User', {
    email: String,
    password: String,
    otp: String,
});
 
// Function to send OTP to the user's email
async function sendOtpEmail(email, otp) {
    try {
        const transporter = nodemailer.createTransport({
            service: 'gmail',
            auth: {
                // replace with your email and password
                user: 'your-email',
                pass: 'your-password',
            },
        });
 
        const mailOptions = {
            from: 'your@gmail.com',
            to: email,
            subject: 'OTP Verification',
            text: `Your OTP is: ${otp}`,
        };
 
        const info =
            await transporter.sendMail(mailOptions);
        console.log('Email sent: ' + info.response);
    } catch (error) {
        console.error('Error sending email:', error);
    }
}
 
app.post('/auth/login', async (req, res) => {
    const { email, password } = req.body;
    console.log(req.body)
 
    try {
        const user = await User.findOne({ email, password });
        console.log(user)
        if (!user) {
            return res.json(
                {
                    success: false,
                    message: 'Invalid credentials'
                }
            );
        }
 
        const generatedOtp = randomize('0', 6);
        user.otp = generatedOtp;
        await user.save();
 
        sendOtpEmail(email, generatedOtp);
 
        return res.json({ success: true });
    } catch (error) {
        console.error('Error during login:', error.message);
        return res.status(500).json(
            {
                success: false,
                message: 'An error occurred during login'
            }
        );
    }
});
 
app.post('/auth/verify-otp', async (req, res) => {
    const { otp } = req.body;
 
    try {
        const user = await User.findOne({ otp });
 
        if (!user) {
            return res.json({ success: false, message: 'Invalid OTP' });
        }
 
        user.otp = '';
        await user.save();
 
        return res.json({ success: true });
    } catch (error) {
        console.error('Error during OTP verification:', error.message);
        return res.status(500)
            .json(
                {
                    success: false,
                    message: 'An error occurred during OTP verification'
                }
            );
    }
});
 
app.listen(PORT, () => {
    console.log(`Server is running on http://localhost:${PORT}`);
});


Step to Run Application: Run the application using the following command from the root directory of the project.

Start the server:

cd server
node server.js

Start the client:

cd client
npm start

Output: Open your browser and go to http://localhost:3000 to view the application.

output

Output of the project



Like Article
Suggest improvement
Previous
Next
Share your thoughts in the comments

Similar Reads