Skip to main content

Django DRF OTP Auth

PyPI License: MIT

A reusable Django app for email-based One-Time Password (OTP) authentication, designed for Django REST Framework (DRF) and integrated with dj-rest-auth.

Why OTP?

Passwords are a pain. Users forget them, reuse them, and they are a prime target for attackers. Storing them securely is a liability.

Django DRF OTP Auth solves this by eliminating passwords entirely:

  • 🧠 No Memory Required: Users don't need to remember complex passwords.
  • 💾 Zero Password Storage: You don't have to worry about hashing, salting, or leaking passwords.
  • 🔄 Simplified Flows: No more "Forgot Password" or "Reset Password" complexity.
  • 🛡️ Enhanced Security: OTPs are short-lived and one-time use.

Features

  • 🔐 Secure OTP Generation: Cryptographically secure 6-character alphanumeric codes.
  • ⚡ Cache-Backed: Fast and reliable storage for OTPs with automatic expiration (default 5 minutes).
  • 📧 Email Delivery: Integrated email sending using Django's email backend.
  • 🔌 DRF Integration: Ready-to-use API views for requesting and verifying OTPs.
  • 🎫 JWT Support: Seamlessly integrates with dj-rest-auth to issue JWTs upon verification.
  • ⚙️ Configurable: Customizable project name, email templates, and throttling.
  • 🛡️ Throttling: Built-in support for ScopedRateThrottle to prevent abuse.

Installation

pip install django-drf-otp-auth

Or using uv:

uv add django-drf-otp-auth

Configuration

1. Add to INSTALLED_APPS

Add django_otp_auth to your INSTALLED_APPS in settings.py:

INSTALLED_APPS = [
    ...
    'rest_framework',
    'rest_framework.authtoken',
    'dj_rest_auth',
    'django_otp_auth',
    ...
]

2. Configure REST Framework & Auth

Ensure you have dj-rest-auth and simplejwt configured:

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'dj_rest_auth.jwt_auth.JWTCookieAuthentication',
    ),
    'DEFAULT_THROTTLE_RATES': {
        'otp_request': '5/hour',
        'otp_verify': '10/hour',
    }
}

REST_AUTH = {
    'USE_JWT': True,
    'JWT_AUTH_COOKIE': 'access-token',
    'JWT_AUTH_REFRESH_COOKIE': 'refresh-token',
}

3. Email Configuration

Configure your email backend in settings.py:

EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'smtp.example.com'
EMAIL_PORT = 587
EMAIL_USE_TLS = True
EMAIL_HOST_USER = 'user@example.com'
EMAIL_HOST_PASSWORD = 'password'
DEFAULT_FROM_EMAIL = 'Your App <noreply@example.com>'

4. Optional Settings

Setting Description Default
OTP_AUTH_PROJECT_NAME Project name used in emails 'Lifetivation'
OTP_AUTH_DISABLE_LOCAL_AUTH Enable "Magic OTP" flow (skips email, accepts 000000) False

Local Development (Magic OTP)

To simplify local development and testing, you can enable the "Magic OTP" flow. This allows you to log in as any user using the fixed OTP code 000000, without sending actual emails with the OTP.

  1. Configure the setting in your settings.py to read from an environment variable:
    # Using django-environ
    OTP_AUTH_DISABLE_LOCAL_AUTH = env.bool("OTP_AUTH_DISABLE_LOCAL_AUTH", default=False)
    
  2. Set OTP_AUTH_DISABLE_LOCAL_AUTH=True in your local .env file.
  3. Request an OTP for any email (e.g., test@example.com).
  4. Verify using the code 000000.

Usage

URL Configuration

Include the URLs in your project's urls.py:

from django.urls import path, include
from django_otp_auth.views import RequestOTPView, VerifyOTPView

urlpatterns = [
    # ...
    path('auth/otp/request/', RequestOTPView.as_view(), name='otp_request'),
    path('auth/otp/verify/', VerifyOTPView.as_view(), name='otp_verify'),
    # ...
]

API Endpoints

1. Request OTP

POST /auth/otp/request/

Request a new OTP to be sent to the user's email.

Payload:

{
  "email": "user@example.com"
}

Response:

{
  "message": "OTP sent successfully"
}

2. Verify OTP

POST /auth/otp/verify/

Verify the received OTP. If successful, returns JWT access and refresh tokens (and sets them in cookies if configured).

Payload:

{
  "email": "user@example.com",
  "otp": "ABC123"
}

Response:

{
  "access": "eyJhbGciOiJIUzI1NiIsIn...",
  "user": {
      "pk": 1,
      "email": "user@example.com",
      ...
  }
}

Customization

Email Templates

You can override the email templates by creating the following files in your project's templates directory:

  • templates/emails/otp_email.html
  • templates/emails/otp_email.txt

Context available:

  • otp: The generated OTP code.
  • project_name: The value of OTP_AUTH_PROJECT_NAME.

Development

To run tests locally using uv:

uv run pytest

Metadata

Release files for django-drf-otp-auth 0.1.4

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for django-drf-otp-auth 0.1.4
File Size Uploaded
django_drf_otp_auth-0.1.4.tar.gz 17.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for django-drf-otp-auth 0.1.4
File Interpreter ABI Platform
django_drf_otp_auth-0.1.4-py3-none-any.whl Python 3 none any Details

Total release size: 25.7 kB

Release files / django_drf_otp_auth-0.1.4.tar.gz

Download URL django_drf_otp_auth-0.1.4.tar.gz
Size 17.9 kB
Tags Source
SHA-256 checksum
How to use checksums
91a061a9a49d28be8c9a733c31ecc55df16a17e657df152e3173eb736c59b226
BLAKE2b-256 checksum
How to use checksums
3853a0ed8c11a1ef856ef164039625b99c9f7fe4122b8acabe2aec21d568493a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.9.13 {"installer":{"name":"uv","version":"0.9.13"},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / django_drf_otp_auth-0.1.4-py3-none-any.whl

Download URL django_drf_otp_auth-0.1.4-py3-none-any.whl
Size 7.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
a222b6a4070f5618f10ad33b76c9525ea3bd27aa7b65b2ecc50e2b487476f2e7
BLAKE2b-256 checksum
How to use checksums
c4758299c720ae88ce5da089233264afb3d5ee4eaba9a5e140dbca1646c37853
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.9.13 {"installer":{"name":"uv","version":"0.9.13"},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release history Release notifications | RSS feed

This release

0.1.4 This release

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page