Site-wide Two-Factor Authentication enforcement middleware for Django applications using django-allauth
Project description
Django Require 2FA
A production-ready Django package that enforces Two-Factor Authentication (2FA) across your entire application.
Why This Exists
The Django-Allauth Gap
Django-allauth provides excellent 2FA functionality, but intentionally does not include site-wide 2FA enforcement. This decision was made explicit in:
- PR #3710 - A middleware approach was proposed but rejected by the maintainer
- Issue #3649 - Community discussed various enforcement strategies, issue was closed without implementation
The django-allauth maintainer's position:
"leave such functionality for individual projects to implement"
The Enterprise Need
Many organizations need to:
- Enforce 2FA for all users (not optional)
- Configure 2FA requirements at runtime (not hardcoded)
- Support SaaS/multi-tenant scenarios with organization-level policies
- Maintain audit trails of security configuration changes
Since django-allauth won't provide this, there's a clear market need for a standalone solution.
Our Solution
What We Built
This package provides what the rejected django-allauth PR attempted, but with significant improvements:
| Feature | Rejected PR #3710 | Our Implementation |
|---|---|---|
| URL Matching | String prefix matching (vulnerable) | Proper Django URL resolution |
| Configuration | Hardcoded settings | Runtime admin configuration |
| Testing | Basic tests | 15 comprehensive security tests |
| Security | Known vulnerabilities | Production-hardened |
| Admin Protection | Exempt admin login | Proper 2FA for admin access |
Key Security Features
- Vulnerability Protection: Fixed Issue #173 path traversal attacks
- URL Resolution: Uses Django's proper URL resolution instead of dangerous string matching
- Configuration Validation: Prevents dangerous Django settings misconfigurations
- Comprehensive Testing: 15 security tests covering edge cases, malformed URLs, and regression scenarios
- Admin Security: Removed admin login exemption (admins now require 2FA)
Installation
Install from PyPI:
pip install django-allauth-require2fa
Or with uv (recommended):
uv add django-allauth-require2fa
Quick Start
- Add
require2fato yourINSTALLED_APPS:
INSTALLED_APPS = [
# ...
'django.contrib.admin',
'allauth',
'allauth.account',
'allauth.mfa',
'solo',
'require2fa', # Add this
# ...
]
- Add the middleware to your
MIDDLEWAREsetting:
MIDDLEWARE = [
# ... other middleware
'require2fa.middleware.Require2FAMiddleware', # Add this
]
- Run migrations:
python manage.py migrate require2fa
- Configure in Django Admin:
- Go to Django Admin → Two-Factor Authentication Configuration
- Check "Require Two-Factor Authentication"
- Changes take effect immediately (no restart required)
How It Works
- Authenticated users without 2FA are redirected to
/accounts/2fa/ - Exempt URLs (login, logout, 2FA setup) remain accessible
- Static/media files are automatically detected and exempted
- Admin access requires 2FA verification (security improvement)
Configuration
Runtime Configuration
Visit Django Admin → Two-Factor Authentication Configuration:
- Require Two-Factor Authentication: Toggle 2FA enforcement site-wide
- Changes take effect immediately (no server restart required)
Architecture
- Django-Solo Pattern: Runtime configuration via admin interface
- Middleware Approach: Site-wide enforcement without code changes
- Allauth Integration: Works seamlessly with django-allauth's MFA system
- Production Ready: Data migrations, backward compatibility, zero downtime
Requirements
- Python: 3.12+
- Django: 4.2+
- django-allauth: 0.57.0+
- django-solo: 2.0.0+
Testing
This package includes 15 comprehensive security tests covering:
- URL resolution edge cases
- Malformed URL handling
- Static file exemptions
- Admin protection
- Configuration security
- Regression tests for known vulnerabilities
# Run tests (standalone package)
python -m django test require2fa.tests --settings=require2fa.tests.settings
# Or in a Django project (after installation)
python manage.py test require2fa
Security
This middleware is security-critical. Key protections include:
- Path Traversal Protection: Fixed vulnerability where
/accounts/../admin/could bypass 2FA - URL Resolution: Uses Django's URL dispatcher, not string matching
- Configuration Validation: Prevents dangerous Django settings that would bypass security
- Comprehensive Testing: 15 security-focused tests ensure no regressions
- Security Logging: Uses dedicated
security.2falogger for audit trails
Contributing
Contributions are welcome! Please ensure:
- Security first - any middleware changes need security review
- Comprehensive testing - maintain the 15-test security suite
- Backward compatibility - consider migration paths
- Code quality - use pre-commit hooks (
pre-commit install)
Development Setup
# Clone the repository
git clone https://github.com/heysamtexas/django-allauth-require2fa.git
cd django-allauth-require2fa
# Install uv (if not already installed)
curl -LsSf https://astral.sh/uv/install.sh | sh
# Set up development environment (one command!)
make dev-setup
# Run tests to verify setup
make test
Development Commands
The project uses a Makefile for convenient development tasks:
# Testing and Quality
make test # Run Django tests
make quality # Run all code quality checks (format, lint, security, mypy)
make all # Full workflow (install + quality + test)
# Individual Quality Checks
make format # Auto-format code with ruff
make lint # Check code style with ruff
make security # Run security scan with bandit
make mypy # Run type checking
# Development Utilities
make clean # Clean up generated files
make help # Show all available commands
Manual Commands (Alternative)
If you prefer running commands directly:
# Install and setup
uv sync --dev
uv run pre-commit install
# Testing
uv run python -m django test require2fa.tests --settings=require2fa.tests.settings
# Code quality
uv run ruff format .
uv run ruff check .
uv run bandit -r require2fa/
uv run mypy require2fa/
License
MIT License - see LICENSE file for details.
Changelog
See CHANGELOG.md for version history.
Note: This package fills the gap left by django-allauth's intentional decision not to include site-wide 2FA enforcement. It provides enterprise-ready security features that many organizations require.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file django_allauth_require2fa-1.2.2.tar.gz.
File metadata
- Download URL: django_allauth_require2fa-1.2.2.tar.gz
- Upload date:
- Size: 78.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.12.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4500c070ac63a92d85c64fab9320cd9a3037295d98ddf92e18de252431c47a66
|
|
| MD5 |
725852e819e1d9d14f69998ffcd8cac3
|
|
| BLAKE2b-256 |
451eb87f3f864849676e127a854c42f9d69bddea16a1119535772ed5836e5ad5
|
Provenance
The following attestation bundles were made for django_allauth_require2fa-1.2.2.tar.gz:
Publisher:
semantic-release.yml on heysamtexas/django-allauth-require2fa
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
django_allauth_require2fa-1.2.2.tar.gz -
Subject digest:
4500c070ac63a92d85c64fab9320cd9a3037295d98ddf92e18de252431c47a66 - Sigstore transparency entry: 423231010
- Sigstore integration time:
-
Permalink:
heysamtexas/django-allauth-require2fa@03e846a3f1de7c8422d3576301c02edf113b04f8 -
Branch / Tag:
refs/heads/master - Owner: https://github.com/heysamtexas
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
semantic-release.yml@03e846a3f1de7c8422d3576301c02edf113b04f8 -
Trigger Event:
push
-
Statement type:
File details
Details for the file django_allauth_require2fa-1.2.2-py3-none-any.whl.
File metadata
- Download URL: django_allauth_require2fa-1.2.2-py3-none-any.whl
- Upload date:
- Size: 17.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.12.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e99f6cbff0425db6ac7682ae52ae8b0b80b65f2ad299cd4aa648e3f66951284d
|
|
| MD5 |
a1a3bc2d4cb029a19e9bbeb814628119
|
|
| BLAKE2b-256 |
c2b1c6e43c9a4b5d55b9b2b27b9332d706f92e98d5cc9bbf5dcdfaad3c09a9ec
|
Provenance
The following attestation bundles were made for django_allauth_require2fa-1.2.2-py3-none-any.whl:
Publisher:
semantic-release.yml on heysamtexas/django-allauth-require2fa
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
django_allauth_require2fa-1.2.2-py3-none-any.whl -
Subject digest:
e99f6cbff0425db6ac7682ae52ae8b0b80b65f2ad299cd4aa648e3f66951284d - Sigstore transparency entry: 423231016
- Sigstore integration time:
-
Permalink:
heysamtexas/django-allauth-require2fa@03e846a3f1de7c8422d3576301c02edf113b04f8 -
Branch / Tag:
refs/heads/master - Owner: https://github.com/heysamtexas
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
semantic-release.yml@03e846a3f1de7c8422d3576301c02edf113b04f8 -
Trigger Event:
push
-
Statement type: