Install & Compatibility
Where this runs
tested against v1.18.1 · pip install
no network on importno background threads
Install × environment matrix
Each cell = how many times install + import succeeded across repeated harness runs. Partial = flaky.
glibc = Debian/Ubuntu slim · musl = Alpine Linux
muslpy 3.10–3.915 runs
installs and imports cleanly · install 0.0s · import 0.000s · 93.2MB
glibcpy 3.10–3.915 runs
installs and imports cleanly · install 5.4s · import 0.000s · 94MB
91MB installed
● package 91MB
Code
Verified usage
Verified import paths — ran on the pinned version, not inferred.
urlpatterns
✓ from two_factor.urls import urlpatterns
✗ from two_factor.urls import urlpatterns
Install the library, add `django_otp` and `two_factor` (and any desired plugins) to `INSTALLED_APPS`, and ensure `OTPMiddleware` is in `MIDDLEWARE`. Then, configure `LOGIN_URL` and `LOGIN_REDIRECT_URL` to point to the library's views, and include its URL patterns in your project's `urls.py`. Remember to run `python manage.py migrate` after setup.
import os
# settings.py
# Add required apps, ensuring 'two_factor' is listed after django_otp plugins
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'django_otp',
'django_otp.plugins.otp_static',
'django_otp.plugins.otp_totp',
# Optional plugins:
# 'django_otp.plugins.otp_email', # For email tokens
# 'two_factor.plugins.phonenumber', # For SMS/call tokens
# 'two_factor.plugins.email', # For email tokens (alternative)
# 'two_factor.plugins.yubikey', # For YubiKey support
# 'webauthn', # For WebAuthn support
'two_factor',
]
# Add OTP middleware after AuthenticationMiddleware
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django_otp.middleware.OTPMiddleware', # Must be after AuthenticationMiddleware
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
# Point to the two-factor authentication login/profile URLs
LOGIN_URL = 'two_factor:login'
LOGIN_REDIRECT_URL = 'two_factor:profile'
# Optional: Configure email backend if using email tokens
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
DEFAULT_FROM_EMAIL = os.environ.get('DEFAULT_FROM_EMAIL', 'webmaster@localhost')
# urls.py
from django.contrib import admin
from django.urls import path, include
from two_factor.urls import urlpatterns as tf_urls
urlpatterns = [
path('admin/', admin.site.urls),
path('', include(tf_urls)), # Include two-factor URLs at the root or desired path
# path('account/', include(tf_urls)), # Alternative: include at a specific path
]
# To integrate with Django Admin (optional, and usually patched automatically)
# from two_factor.admin import AdminSiteOTPRequiredMixin
# class OTPAdminSite(AdminSiteOTPRequiredMixin, admin.AdminSite):
# pass
# admin.site = OTPAdminSite() # Replace default admin site if needed, often not required.
Debug
Known issues
breakingIn version 1.14.0, the phone capability was moved to a separate plugin. If you used phone-based authentication, you must add 'two_factor.plugins.phonenumber' to your INSTALLED_APPS to restore this functionality.fixAdd 'two_factor.plugins.phonenumber' to your `INSTALLED_APPS` setting.
affects: >=1.14.0
gotchaThe `django_otp.middleware.OTPMiddleware` must be placed in `MIDDLEWARE` *after* `django.contrib.auth.middleware.AuthenticationMiddleware`. Incorrect ordering can lead to authentication issues.fixEnsure `OTPMiddleware` is correctly positioned after `AuthenticationMiddleware` in your `settings.py`.
affects: All versions
gotchaIf using optional authentication methods (e.g., SMS, email, YubiKey, WebAuthn), ensure their respective plugins (e.g., `django_otp.plugins.otp_email`, `two_factor.plugins.phonenumber`) are correctly listed in `INSTALLED_APPS` and any necessary extra dependencies are installed.fixReview the documentation for the specific authentication method and add the required plugin to `INSTALLED_APPS` and install extra packages.
affects: All versions
breakingIn version 1.16.0, the minimal `webauthn` dependency was upgraded to 2.0, which removed its `pydantic` dependency. If you were relying on `pydantic` through `webauthn`, you might need to add it as a direct dependency.fixIf `pydantic` is still needed for other parts of your project, install it directly (`pip install pydantic`).
affects: >=1.16.0
gotchaTo prevent circumvention of two-factor authentication, ensure that any other login routes in your project (e.g., `django.contrib.auth.urls`) are removed or disabled once `django-two-factor-auth` is configured as the primary login.fixCarefully review your project's `urls.py` and remove or comment out conflicting login URL patterns, especially `path('accounts/', include('django.contrib.auth.urls'))` if it's not being explicitly handled. affects: All versions
gotchaPrior to 1.18.0, the documentation for setting up YubiKey support or email gateways occasionally missed informing users to add the corresponding `django-otp` or `two_factor` plugin to `INSTALLED_APPS`. This was fixed in docs, but the underlying common mistake remains.fixAlways ensure relevant plugins (`django_otp.plugins.otp_yubikey`, `two_factor.plugins.email`, etc.) are in `INSTALLED_APPS`.
affects: <1.18.0 (docs), All versions (common mistake)
gotchaAn infinite redirect issue with `AdminSiteOTPRequiredMixin` on the admin site was fixed in 1.18.0. If you are using this mixin, ensure you are on a compatible version to avoid login loops.fixUpgrade to `django-two-factor-auth` version 1.18.0 or newer if using `AdminSiteOTPRequiredMixin`.
affects: <1.18.0
Upgrade
Version history
1.18.1latest on PyPI · released Sep 27, 2025
Audit
Dependencies
django-otprequiredCore one-time password framework.
qrcoderequiredUsed for generating QR codes for TOTP setup.
django-phonenumber-fieldoptionalRequired for phone number capabilities (SMS, call).
phonenumbersoptionalRequired by django-phonenumber-field.
phonenumbersliteoptionalAlternative to phonenumbers, required by django-phonenumber-field.
webauthnoptionalFor WebAuthn (FIDO2) support.
django-otp-yubikeyoptionalFor YubiKey hardware token support.
PillowoptionalOptional, for generating PNG QR codes (default is SVG).