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:
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:
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:
// 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(
{
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(
{
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;
|
// 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:
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.