Multi Factor authentication using MERN
Last Updated :
23 Jul, 2025
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:
Output PreviewPrerequisites / 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 structurepackage.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
mongoose.connect('mongodb://127.0.0.1:27017/mfa-mern', {
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: '[email protected]',
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 of the project