python

Is Your FastAPI App Missing This Essential Security Feature?

Bolstering Digital Fortresses: FastAPI & Two-Factor Authentication

Is Your FastAPI App Missing This Essential Security Feature?

Implementing two-factor authentication (2FA) in FastAPI is a game-changer for securing your web application. It’s like adding an extra lock on your door, but for your online space. By asking users to give two kinds of info to log in—a password they know and a one-time password (OTP) from an authenticator app—it raises the security bar higher.

Two-factor authentication (2FA) steps up security by adding another hurdle for any unwanted visitors. Picture it as a multi-layered fortress for user accounts. When logging in, users not only enter their passwords but also a special, time-sensitive OTP from an app like Google Authenticator. This OTP renews every 30 seconds, making it super tough for anyone to break in.

Getting started with 2FA in FastAPI involves a series of straightforward steps. First up, you need specific libraries to get the ball rolling. Use FastAPI, Uvicorn to run the server, pyotp to create and check those handy OTPs, and qrcode to whip up QR codes for scanning. Just hit your terminal and type:

pip install fastapi uvicorn pyotp qrcode

When it comes to making a FastAPI app, start simple. Set up routes for registering users, logging in, and getting the 2FA setup.

from fastapi import FastAPI, Depends, HTTPException, Response
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
from pyotp import TOTP
from qrcode import QRCode
from io import BytesIO
from typing import Optional

app = FastAPI()

class SecuritySettings:
    otp_configured: bool
    secret: Optional[str]

class User:
    username: str
    password: str
    security_settings: SecuritySettings

users = {}

async def get_current_user(token: HTTPAuthorizationCredentials = Depends()):
    if token is None:
        raise HTTPException(status_code=401, detail="Unauthorized")
    return users.get(token.credentials)

For user registration, a new secret key for 2FA is generated and saved in the user’s profile. Check this out:

@app.post("/signup")
async def signup(username: str, password: str):
    if username in users:
        raise HTTPException(status_code=400, detail="Username already exists")
    secret = TOTP.random_base32()
    users[username] = User(username=username, password=password, security_settings=SecuritySettings(otp_configured=False, secret=secret))
    return {"message": "User created successfully"}

To set up the 2FA process, generating a QR code is key. This QR holds all the info the authenticator app needs to generate those magic OTPs.

@app.get("/auth/otp/generate")
async def generate_qr_code(user: User = Depends(get_current_user)):
    totp = TOTP(user.security_settings.secret)
    uri = totp.provisioning_uri(name=user.username, issuer_name="Example App")
    qr = QRCode()
    qr.add_data(uri)
    img = qr.make_image()
    img_byte_arr = BytesIO()
    img.save(img_byte_arr, format="PNG")
    img_byte_arr = img_byte_arr.getvalue()
    return Response(content=img_byte_arr, media_type="image/png")

Once the QR code is ready, the user needs to enable 2FA. This involves scanning the QR and verifying with the first OTP generated.

@app.put("/auth/otp/enable")
async def enable_2fa(user: User = Depends(get_current_user), otp: str):
    totp = TOTP(user.security_settings.secret)
    if totp.verify(otp):
        user.security_settings.otp_configured = True
        return {"message": "2FA enabled successfully"}
    else:
        raise HTTPException(status_code=400, detail="Invalid OTP")

Finally, logging in becomes a two-step process now. The user must input both their password and the current OTP.

@app.post("/login")
async def login(username: str, password: str, otp: str):
    user = users.get(username)
    if user is None or user.password != password:
        raise HTTPException(status_code=401, detail="Unauthorized")
    if not user.security_settings.otp_configured:
        raise HTTPException(status_code=400, detail="2FA not enabled")
    totp = TOTP(user.security_settings.secret)
    if not totp.verify(otp):
        raise HTTPException(status_code=400, detail="Invalid OTP")
    return {"message": "Logged in successfully"}

A user journey with this setup goes like this: First, they sign up with a username and password. Then, they head to the QR code endpoint to get that crucial QR code. After scanning the QR code and generating their first OTP, they hit the endpoint to enable 2FA. When all set up, logging in now requires their password and the OTP from their app.

Embracing two-factor authentication in FastAPI is like fortifying your digital castle, making it tougher for anyone to waltz through your gates uninvited. This guide walked through the crucial steps of setting up 2FA with TOTP and authenticator apps, ensuring only those with the right OTPs gain access.

As you fortify your FastAPI playground, always handle user data with iron-clad security and think about adding more layers of protection like role-based access control and tightened error handling. This way, your application stands strong against the dark forces of unauthorized access.

Keywords: two-factor authentication, FastAPI security, enable 2FA, TOTP setup, OTP authentication, secure web apps, Google Authenticator, FastAPI tutorial, QR code generation, login security



Similar Posts
Blog Image
Unlock GraphQL Power: FastAPI and Strawberry for High-Performance APIs

FastAPI and Strawberry combine to create efficient GraphQL APIs. Key features include schema definition, queries, mutations, pagination, error handling, code organization, authentication, and performance optimization using DataLoader for resolving nested fields efficiently.

Blog Image
Is Your Web App's Front Door Secure with OAuth 2.0 and FastAPI?

Cracking the Security Code: Mastering OAuth 2.0 with FastAPI for Future-Proof Web Apps

Blog Image
Unlock Python's Hidden Power: Mastering Metaclasses for Next-Level Programming

Python metaclasses control class creation and behavior. They customize class attributes, enforce coding standards, implement design patterns, and add functionality across class hierarchies. Powerful but complex, metaclasses should be used judiciously to enhance code without sacrificing clarity.

Blog Image
Marshmallow and Flask-RESTful: Building Scalable APIs with Ease

Flask, Flask-RESTful, and Marshmallow create a powerful ecosystem for building scalable APIs. They simplify development, handle data serialization, and provide robust validation, making API creation efficient and maintainable.

Blog Image
Exploring Python’s Data Model: Customizing Every Aspect of Python Objects

Python's data model empowers object customization through special methods. It enables tailored behavior for operations, attribute access, and resource management. This powerful feature enhances code expressiveness and efficiency, opening new possibilities for Python developers.

Blog Image
How Can You Lock Down Your FastAPI App with OAuth2 in a Snap?

Unlocking Robust Security: Implementing OAuth2 Password Flow in FastAPI