DEV Community

Cover image for Adding TOTP-Based 2FA to Django REST Framework with django-totp
Kumar Sahil
Kumar Sahil

Posted on

Adding TOTP-Based 2FA to Django REST Framework with django-totp

Two-factor authentication (2FA) is becoming a standard requirement for modern applications, especially for APIs that use JWT authentication or separate frontend/backend architectures.

While working on Django REST Framework projects, I wanted a lightweight and API-focused way to add TOTP authentication without depending heavily on template-based flows or admin integrations.

So I built django-totp.

It is a reusable Django package that provides:

  • TOTP enrollment
  • QR generation
  • backup recovery codes
  • encrypted secret storage
  • DRF endpoints
  • helper utilities for multi-step authentication flows

PyPI: django-totp

Requirements

  • Python 3.12+
  • Django 5.0+
  • Django REST Framework 3.15+

Installation

Install the package from PyPI:

pip install django-totp
Enter fullscreen mode Exit fullscreen mode

Add the apps to your Django settings:

INSTALLED_APPS = [
    # Django apps...
    "rest_framework",
    "django_totp",
]
Enter fullscreen mode Exit fullscreen mode

Configure the Encryption Key

TOTP secrets and backup codes are stored using Fernet encryption.

Generate a key once

python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())"
Enter fullscreen mode Exit fullscreen mode

Add it to your environment

TOTP_ENCRYPTION_KEY=your-generated-key
Enter fullscreen mode Exit fullscreen mode

Load it in Django settings

import os

TOTP_ENCRYPTION_KEY = os.environ["TOTP_ENCRYPTION_KEY"]
Enter fullscreen mode Exit fullscreen mode

Include the URLs

from django.urls import include, path

urlpatterns = [
    path("api/", include("django_totp.urls")),
]
Enter fullscreen mode Exit fullscreen mode

Run migrations:

python manage.py migrate
Enter fullscreen mode Exit fullscreen mode

Available Endpoints

The package provides endpoints for the full enrollment lifecycle.

Create Enrollment

POST /api/totp/create/
Enter fullscreen mode Exit fullscreen mode

Creates a TOTP secret and returns an SVG QR code.

Example response:

{
    "svg": "<svg ...>...</svg>"
}
Enter fullscreen mode Exit fullscreen mode

Confirm Enrollment

POST /api/totp/confirm/
Enter fullscreen mode Exit fullscreen mode

Request:

{
    "input_code": "123456"
}
Enter fullscreen mode Exit fullscreen mode

Successful confirmation returns backup recovery codes.

Disable TOTP

POST /api/totp/disable/
Enter fullscreen mode Exit fullscreen mode

Disables TOTP and removes backup codes.

Rotate Backup Codes

POST /api/totp/rotate_backup_codes/
Enter fullscreen mode Exit fullscreen mode

Generates a new backup code set.

Example Login Flow

A common authentication flow looks like this:

1. Validate username/password
2. Check whether the user has TOTP enabled
3. Issue a temporary challenge token
4. Ask for TOTP or backup code
5. Verify the code
6. Issue final JWT/session
Enter fullscreen mode Exit fullscreen mode

The package includes helper utilities for this flow.

Example:

from django_totp.auth import (
    generate_challenge_token,
    is_totp_enabled,
)

from django_totp.totp import verify_totp_code
Enter fullscreen mode Exit fullscreen mode

Other Utilities

Useful helpers you can import directly:

  • django_totp.auth
    • is_totp_enabled(user)
    • generate_challenge_token(user)
    • verify_challenge_token(token)
    • get_user_from_challenge_token(token)
  • django_totp.totp
    • generate_totp_secret()
    • verify_totp_code(user, input_code)
    • create_totp_setup(user)
    • confirm_totp_setup(user, input_code)
    • disable_totp(user)
  • django_totp.backup_code_utils
    • store_backup_codes(user, codes)
    • verify_backup_code(user, input_code)
    • rotate_backup_codes(user)
  • django_totp.encryption
    • generate_fernet_key()
    • resolve_fernet_key(default=None)
    • encrypt(value)
    • decrypt(value)

Features

The package currently includes:

  • Encrypted TOTP secret storage
  • QR generation for authenticator apps
  • Backup code generation and rotation
  • One-time-use backup code validation
  • DRF integration
  • Configurable issuer name
  • Endpoint throttling support
  • Signed temporary challenge tokens

Why I Built It

Many existing Django 2FA solutions are designed primarily for server-rendered applications.

I wanted something focused more on:

  • DRF APIs
  • JWT authentication flows
  • SPA/mobile frontends
  • reusable API endpoints

The goal was to keep the package relatively lightweight while still covering common 2FA requirements.

Project Links

Feedback, issues, and contributions are welcome.

Top comments (0)