Multi‐Factor Authentication (MFA) - sonuprajapati15/Authentication-Authorization GitHub Wiki

System Design: Multi-Factor Authentication (MFA)

1. Overview

Multi-Factor Authentication (MFA) enhances security by requiring users to verify their identity using two or more authentication factors before accessing a system.

🔹 Common MFA factors:

  1. Something You Know – Password, PIN, security questions.
  2. Something You Have – OTP (One-Time Password via SMS, Email, Authenticator App).
  3. Something You Are – Biometrics (Fingerprint, Face Recognition).

🔹 Example: Logging into a banking app with a password and then confirming the login with a one-time code sent to your phone.


2. Functional & Non-Functional Requirements

Functional Requirements

✅ Users can enable or disable MFA.
✅ Supports multiple authentication factors (TOTP, SMS, Email, Push Notification, Biometrics).
✅ After entering a password, the user must complete a second verification step.
✅ Users can reset MFA settings if they lose access to their second factor.
✅ Remember device option for a seamless login experience.

Non-Functional Requirements

Security – Protect against phishing, replay attacks, and brute-force attacks.
Scalability – Efficiently handle large numbers of MFA requests.
Performance – Generate and validate OTPs quickly without delay.
Availability – Ensure fallback methods (backup codes) in case primary MFA is unavailable.
Compliance – Must follow GDPR, PCI-DSS, HIPAA for sensitive authentication data.


3. High-Level Design (HLD)

Architecture Components

  1. User (Client) – Initiates login and completes MFA verification.
  2. Authentication Server – Handles login, generates and verifies MFA codes.
  3. MFA Provider – Sends OTPs via SMS, Email, or Authenticator App (e.g., Google Authenticator).
  4. MFA Storage – Stores user MFA settings (enabled methods, backup codes).

MFA Authentication Flow

  1. User logs in with username & password → If correct, proceed to MFA.
  2. MFA challenge → The system sends an OTP via SMS, Email, or an Authenticator App.
  3. User enters OTP → The authentication server verifies it.
  4. Success → User gains access, and a session is created.
  5. Failure → User is denied access and may retry or use a backup method.

4. Low-Level Design (LLD)

Database Schema

CREATE TABLE users (
    id SERIAL PRIMARY KEY,
    username VARCHAR(255) UNIQUE NOT NULL,
    password_hash TEXT NOT NULL,
    email VARCHAR(255) UNIQUE NOT NULL,
    phone VARCHAR(20),
    mfa_enabled BOOLEAN DEFAULT FALSE,
    mfa_method VARCHAR(20) CHECK (mfa_method IN ('totp', 'sms', 'email'))
);

CREATE TABLE mfa_codes ( id SERIAL PRIMARY KEY, user_id INT REFERENCES users(id) ON DELETE CASCADE, otp_code VARCHAR(10) NOT NULL, expires_at TIMESTAMP NOT NULL, used BOOLEAN DEFAULT FALSE );

API Endpoints

Method Endpoint Description
POST /login Authenticate user with username/password
POST /mfa/verify Verify OTP from SMS, Email, or Authenticator App
POST /mfa/setup Enable/disable MFA for a user
GET /mfa/backup Retrieve backup codes for MFA recovery
POST /logout Terminate session

6. Diagrams

Here is the MFA Authentication Flowchart:

MFA Authentication Flow

View or edit this diagram in Whimsical.


7. Code Implementation (Node.js + Express + TOTP + Twilio SMS)

1. Install Dependencies

npm install express bcrypt jsonwebtoken speakeasy twilio dotenv

2. Setup Express Server with MFA (TOTP & SMS)

require("dotenv").config();
const express = require("express");
const bcrypt = require("bcrypt");
const jwt = require("jsonwebtoken");
const speakeasy = require("speakeasy");
const twilio = require("twilio");

const app = express(); app.use(express.json());

// Mock user database const users = [ { id: 1, username: "user1", passwordHash: bcrypt.hashSync("password", 10), mfaSecret: null, phone: "+1234567890", mfaEnabled: false } ];

// Twilio Client const twilioClient = new twilio(process.env.TWILIO_SID, process.env.TWILIO_AUTH_TOKEN);

// Login Route app.post("/login", async (req, res) => { const { username, password } = req.body; const user = users.find((u) => u.username === username);

if (!user || !(await bcrypt.compare(password, user.passwordHash))) { return res.status(401).json({ message: "Invalid credentials" }); }

if (user.mfaEnabled) { const token = jwt.sign({ userId: user.id }, process.env.JWT_SECRET, { expiresIn: "5m" }); return res.json({ mfaRequired: true, token }); }

res.json({ message: "Login successful", token: jwt.sign({ userId: user.id }, process.env.JWT_SECRET) }); });

// MFA Verification Route app.post("/mfa/verify", (req, res) => { const { token, otp } = req.body; const decoded = jwt.verify(token, process.env.JWT_SECRET); const user = users.find((u) => u.id === decoded.userId);

if (!speakeasy.totp.verify({ secret: user.mfaSecret, encoding: "base32", token: otp })) { return res.status(400).json({ message: "Invalid OTP" }); }

res.json({ message: "MFA Successful", token: jwt.sign({ userId: user.id }, process.env.JWT_SECRET) }); });

app.listen(3000, () => console.log("MFA Server running on port 3000"));


MFA Types Supported

TOTP (Time-based One-Time Passwords) – Google Authenticator, Authy.
SMS/Email OTP – Sends a one-time code to registered phone/email.
Push Notifications – Approve login from a trusted device.
Biometric Authentication – Face ID, fingerprint scan (for mobile apps).


5. Trade-offs & Scalability

Factor Trade-off
Security TOTP is more secure than SMS, as SMS is vulnerable to SIM-swapping.
User Experience Too many MFA prompts can frustrate users; "Remember this device" helps.
Performance OTPs should expire quickly and be rate-limited to prevent brute-force attacks.
Scalability MFA providers (Twilio, Google Authenticator) must handle high request volumes.

Extending Multi-Factor Authentication (MFA) with Additional Methods

Now, let's enhance our MFA system by adding the following authentication methods:

Push Notifications (Firebase Cloud Messaging - FCM) – Users receive an approval request on their phone.
Backup Codes – Pre-generated one-time use codes for emergency access.
Biometric Authentication – Face ID or Fingerprint for mobile apps.


1. Updated High-Level Design (HLD)

New Components

  1. Push Notification Service (FCM/APNs) – Sends login approval requests to mobile devices.
  2. Backup Codes Database – Stores one-time codes for emergency login.
  3. Biometric Authentication – Integrates Face ID or Fingerprint for mobile users.

Updated MFA Workflow

  1. User logs in – Password verification is successful.
  2. MFA Challenge – User selects one of the MFA methods:
    • OTP (SMS/Email) – Enter the code sent via SMS or email.
    • Authenticator App (TOTP) – Enter the time-based OTP.
    • Push Notification (Firebase/APNs) – Approve login request from a mobile app.
    • Biometric Authentication – Authenticate using Face ID/Fingerprint (if enabled).
    • Backup Code – Use a previously generated one-time backup code.
  3. Authentication Server Validates MFA Response.
  4. Successful Authentication → User gains access.

2. Updated Low-Level Design (LLD)

Updated Database Schema

CREATE TABLE mfa_methods (
    id SERIAL PRIMARY KEY,
    user_id INT REFERENCES users(id) ON DELETE CASCADE,
    method VARCHAR(20) CHECK (method IN ('totp', 'sms', 'email', 'push', 'biometric', 'backup_code')),
    secret TEXT,
    enabled BOOLEAN DEFAULT TRUE
);

CREATE TABLE backup_codes ( id SERIAL PRIMARY KEY, user_id INT REFERENCES users(id) ON DELETE CASCADE, code VARCHAR(10) NOT NULL, used BOOLEAN DEFAULT FALSE );

New API Endpoints

Method Endpoint Description
POST /mfa/verify Verify OTP, push notification, or biometric auth
GET /mfa/push/send Send push notification request
POST /mfa/push/approve Approve or reject push notification request
GET /mfa/backup Retrieve backup codes
POST /mfa/backup/use Use a backup code for login

4. Diagrams

Here is the Enhanced MFA Authentication Flowchart:

Enhanced MFA Authentication Flow

View or edit this diagram in Whimsical.


5. Code Implementation (Node.js + Firebase Push + Backup Codes + Biometric Auth)

1. Install Dependencies

npm install express bcrypt jsonwebtoken speakeasy twilio firebase-admin dotenv

2. Setup Express Server with Multiple MFA Methods

require("dotenv").config();
const express = require("express");
const bcrypt = require("bcrypt");
const jwt = require("jsonwebtoken");
const speakeasy = require("speakeasy");
const twilio = require("twilio");
const admin = require("firebase-admin");

const app = express(); app.use(express.json());

// Firebase Push Notification Setup admin.initializeApp({ credential: admin.credential.cert(require("./firebase-key.json")) });

// Mock user database const users = [ { id: 1, username: "user1", passwordHash: bcrypt.hashSync("password", 10), mfaSecret: speakeasy.generateSecret().base32, phone: "+1234567890", mfaEnabled: true, pushToken: "user_fcm_token" } ];

// Twilio Client const twilioClient = new twilio(process.env.TWILIO_SID, process.env.TWILIO_AUTH_TOKEN);

// Login Route app.post("/login", async (req, res) => { const { username, password } = req.body; const user = users.find((u) => u.username === username);

if (!user || !(await bcrypt.compare(password, user.passwordHash))) { return res.status(401).json({ message: "Invalid credentials" }); }

if (user.mfaEnabled) { const token = jwt.sign({ userId: user.id }, process.env.JWT_SECRET, { expiresIn: "5m" }); return res.json({ mfaRequired: true, token }); }

res.json({ message: "Login successful", token: jwt.sign({ userId: user.id }, process.env.JWT_SECRET) }); });

// Push Notification MFA app.get("/mfa/push/send", (req, res) => { const { userId } = jwt.verify(req.headers.authorization, process.env.JWT_SECRET); const user = users.find((u) => u.id === userId);

admin.messaging().send({ token: user.pushToken, notification: { title: "Login Request", body: "Approve login attempt?" } });

res.json({ message: "Push notification sent" }); });

// MFA Verification app.post("/mfa/verify", (req, res) => { const { token, otp } = req.body; const decoded = jwt.verify(token, process.env.JWT_SECRET); const user = users.find((u) => u.id === decoded.userId);

if (!speakeasy.totp.verify({ secret: user.mfaSecret, encoding: "base32", token: otp })) { return res.status(400).json({ message: "Invalid OTP" }); }

res.json({ message: "MFA Successful", token: jwt.sign({ userId: user.id }, process.env.JWT_SECRET) }); });

app.listen(3000, () => console.log("MFA Server running on port 3000"));



3. Trade-offs & Considerations

MFA Method Pros Cons
TOTP (Authenticator App) Secure, no internet required User needs an app like Google Authenticator
SMS/Email OTP Easy to use Susceptible to SIM swapping & phishing
Push Notifications Seamless UX, secure Requires internet & mobile app
Biometric Authentication Fast & secure Device-dependent
Backup Codes Emergency access Must be stored securely by the user

6. Conclusion

Now, our MFA system supports SMS, TOTP, Push Notifications, Backup Codes, and Biometrics! This makes it more secure and user-friendly.

learn WebAuthn (FIDO2) for passwordless authentication 🚀

⚠️ **GitHub.com Fallback** ⚠️