Multi-factor Authentication (MFA) in FastAPI#

Multi-factor Authentication (MFA) is a security mechanism that requires users to verify their identity using multiple factors. These factors are typically categorized into:

  1. Something you know: A password or PIN.

  2. Something you have: A smartphone or a hardware token.

  3. Something you are: Biometrics, such as a fingerprint or facial recognition.

By combining multiple factors, MFA significantly reduces the risk of unauthorized access, even if one factor (e.g., a password) is compromised.

Advantages of MFA: - Enhanced Security: Even if passwords are stolen, attackers cannot access the system without the additional authentication factor. - Reduced Risk of Identity Theft: MFA makes it harder for attackers to impersonate users. - Compliance with Regulations: Many industries require MFA to comply with standards like GDPR or HIPAA. - User Trust: Implementing MFA shows users that their security is a priority.

This document demonstrates how to implement MFA in a FastAPI application using PyOTP for OTP generation and verification.

👉 New to App-Generator? Sign IN with GitHub or Generate Web Apps in no time (free service).

Overview#

This example uses the following: - FastAPI: For building the web application. - PyOTP: For generating and verifying one-time passwords (OTPs). - Pydantic: For data validation. - SQLite: As the database for simplicity (can be replaced with other DB systems).

Step 1: Install Dependencies#

Install the required Python libraries using pip:

pip install fastapi uvicorn sqlalchemy pyotp sqlite3 pydantic 

Step 2: Create the Database#

Define a simple SQLite database to store user data.

from sqlalchemy import create_engine, Column, Integer, String, Boolean from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import sessionmaker Base = declarative_base() engine = create_engine("sqlite:///mfa_demo.db") SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) class User(Base): __tablename__ = "users" id = Column(Integer, primary_key=True, index=True) username = Column(String, unique=True, index=True) password = Column(String) otp_secret = Column(String) # Stores the OTP secret is_otp_verified = Column(Boolean, default=False) Base.metadata.create_all(bind=engine) 

Step 3: Implement MFA Logic#

  1. Register Users: Allow users to register and generate a unique OTP secret.

  2. Login: Validate username and password, and then request OTP.

  3. Verify OTP: Verify the OTP provided by the user.

from fastapi import FastAPI, Depends, HTTPException from sqlalchemy.orm import Session import pyotp app = FastAPI() def get_db(): db = SessionLocal() try: yield db finally: db.close() @app.post("/register") def register_user(username: str, password: str, db: Session = Depends(get_db)): otp_secret = pyotp.random_base32() new_user = User(username=username, password=password, otp_secret=otp_secret) db.add(new_user) db.commit() db.refresh(new_user) return {"message": "User registered!", "otp_secret": otp_secret} @app.post("/login") def login_user(username: str, password: str, db: Session = Depends(get_db)): user = db.query(User).filter(User.username == username).first() if not user or user.password != password: raise HTTPException(status_code=400, detail="Invalid credentials") return {"message": "Login successful, provide OTP"} @app.post("/verify-otp") def verify_otp(username: str, otp: str, db: Session = Depends(get_db)): user = db.query(User).filter(User.username == username).first() if not user: raise HTTPException(status_code=404, detail="User not found") totp = pyotp.TOTP(user.otp_secret) if not totp.verify(otp): raise HTTPException(status_code=400, detail="Invalid OTP") user.is_otp_verified = True db.commit() return {"message": "OTP verified successfully"} 

Step 4: Test the Application#

  1. Start the Application: Run the FastAPI application using Uvicorn:

    uvicorn main:app --reload 
  2. Register a User: Use a tool like Postman or cURL to register a new user:

    POST /register {  "username": "testuser",  "password": "securepassword" } 

    Response:

    {  "message": "User registered!",  "otp_secret": "JBSWY3DPEHPK3PXP" } 

    Use the otp_secret to set up an OTP generator, such as Google Authenticator.

  3. Login: Authenticate the user using their username and password:

    POST /login {  "username": "testuser",  "password": "securepassword" } 

    Response:

    {  "message": "Login successful, provide OTP" } 
  4. Verify OTP: Verify the OTP provided by the user:

    POST /verify-otp {  "username": "testuser",  "otp": "123456" } 

    Response:

    {  "message": "OTP verified successfully" } 

Conclusion#

This demonstrates a simple implementation of Multi-factor Authentication (MFA) in FastAPI. For production-grade applications, ensure to use encrypted passwords (e.g., bcrypt) and secure storage mechanisms for secrets and sensitive data.