A Django app to support phone number verification using a security code sent via SMS.
django-phone-verify provides a simple, secure way to verify phone numbers for user authentication, 2FA, account recovery, and more. It works seamlessly with Django and Django REST Framework, supports multiple SMS providers (Twilio, Nexmo/Vonage), and is fully extensible with custom backends.
📖 Full Documentation: https://django-phone-verify.readthedocs.io/
What It Does
django-phone-verify handles the complete phone verification flow:
Send Verification Code - User requests verification, receives SMS with security code
Verify Code - User submits code, system validates and confirms phone number
Session Management - Secure JWT-based session tokens prevent tampering
Multiple Use Cases - Registration, 2FA, password reset, marketing opt-in, and more
Key Features
Security & Flexibility
🔐 Secure verification flow - JWT session tokens, configurable code expiration, one-time use options
🔧 Highly customizable - Token length, expiration time, message templates, custom backends
🔒 Production-ready - Rate limiting support, security best practices, GDPR/CCPA compliance guidance
Easy Integration
🚀 Django REST Framework - Pre-built viewsets and serializers for instant API setup
🔌 Pluggable backends - Use Twilio, Nexmo/Vonage, or write your own (AWS SNS, MessageBird, etc.)
✅ Non-intrusive - Works with any AUTH_USER_MODEL, no database changes required to your user model
🧪 Sandbox mode - Test flows without sending real SMS messages
Multiple Use Cases
👤 User registration phone verification
🔑 Two-factor authentication (2FA)
🔄 Account recovery / password reset
📧 Marketing opt-in verification
📱 Phone number update flows
Installation
Install the package with all supported backends:
pip install django-phone-verify[all]
Or install with just the backend you need:
pip install django-phone-verify[twilio]
pip install django-phone-verify[nexmo]
Configuration
Add phone_verify to INSTALLED_APPS:
INSTALLED_APPS = [
...
"phone_verify",
...
]
Run migrations:
python manage.py migrate
Include the API URLs in your project’s urls.py:
from django.urls import path, include
urlpatterns = [
...
path("api/phone/", include("phone_verify.urls")),
...
]
Configure PHONE_VERIFICATION settings in your settings.py:
For Twilio:
PHONE_VERIFICATION = {
"BACKEND": "phone_verify.backends.twilio.TwilioBackend",
"OPTIONS": {
"SID": "your-twilio-account-sid",
"SECRET": "your-twilio-auth-token",
"FROM": "+1234567890", # Your Twilio phone number
"SANDBOX_TOKEN": "123456", # Optional: for testing without sending real SMS
},
"TOKEN_LENGTH": 6,
"MESSAGE": "Welcome to {app}! Please use security code {security_code} to proceed.",
"APP_NAME": "Phone Verify",
"SECURITY_CODE_EXPIRATION_SECONDS": 3600, # in seconds
"VERIFY_SECURITY_CODE_ONLY_ONCE": False,
}
For Nexmo (Vonage):
PHONE_VERIFICATION = {
"BACKEND": "phone_verify.backends.nexmo.NexmoBackend",
"OPTIONS": {
"KEY": "your-nexmo-api-key",
"SECRET": "your-nexmo-api-secret",
"FROM": "YourApp", # Sender ID
"SANDBOX_TOKEN": "123456", # Optional: for testing
},
"TOKEN_LENGTH": 6,
"MESSAGE": "Welcome to {app}! Please use security code {security_code} to proceed.",
"APP_NAME": "Phone Verify",
"SECURITY_CODE_EXPIRATION_SECONDS": 3600,
"VERIFY_SECURITY_CODE_ONLY_ONCE": False,
}
Quick Start
Step 1: Send verification code
curl -X POST http://localhost:8000/api/phone/register/ \
-H "Content-Type: application/json" \
-d '{"phone_number": "+1234567890"}'
# Response:
# {
# "session_token": "eyJ0eXAiOiJKV1QiLCJhbGc...",
# "phone_number": "+1234567890"
# }
Step 2: Verify the code
curl -X POST http://localhost:8000/api/phone/verify/ \
-H "Content-Type: application/json" \
-d '{
"phone_number": "+1234567890",
"security_code": "123456",
"session_token": "eyJ0eXAiOiJKV1QiLCJhbGc..."
}'
# Response:
# {
# "message": "Security code is valid",
# "phone_number": "+1234567890"
# }
Using in Python/Django code:
from phone_verify.services import send_security_code_and_generate_session_token
from phone_verify.services import verify_security_code
# Send verification code via SMS
session_token = send_security_code_and_generate_session_token(
phone_number="+1234567890"
)
# User receives SMS: "Welcome to Phone Verify! Please use security code 847291 to proceed."
# Verify the code user entered
try:
verify_security_code(
phone_number="+1234567890",
security_code="847291",
session_token=session_token
)
print("✓ Phone number verified successfully!")
except Exception as e:
print(f"✗ Verification failed: {e}")
Documentation
Full documentation is available at https://django-phone-verify.readthedocs.io/
Quick Links:
🚀 Advanced Examples (2FA, password reset, marketing opt-in)
Compatibility
Python 3.8+ (Python 3.7 and below are EOL)
Django 2.1+
Django REST Framework 3.9+
Contributing
Found a bug? Want to suggest an improvement or submit a patch?
We welcome contributions! Here’s how you can help:
🐛 Report bugs via GitHub Issues
💡 Suggest features or improvements
🔧 Submit pull requests - please check the contributing guide first
📖 Improve documentation
Before submitting a PR:
Write tests for new features
Ensure all tests pass: pytest
Follow the existing code style
Update documentation if needed
License
This project is licensed under the GPLv3 license.
Changelog
See the full changelog here: 📄 CHANGELOG.rst
Metadata
Release files for django-phone-verify 3.3.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| django_phone_verify-3.3.0.tar.gz | 9.7 MB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| django_phone_verify-3.3.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 9.7 MB
Release files / django_phone_verify-3.3.0.tar.gz
| Download URL | django_phone_verify-3.3.0.tar.gz |
|---|---|
| Size | 9.7 MB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
fb6e8df5fba8141b6674f1c7a18cd31faa622299218ecd5e2162d407a35bab8b
|
|
BLAKE2b-256 checksum How to use checksums |
d1980dc1067e43ee12cc5067bfa3d8c09bbf2908c83d5b1e2ca01f149f5ce968
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.10.9
|
Release files / django_phone_verify-3.3.0-py3-none-any.whl
| Download URL | django_phone_verify-3.3.0-py3-none-any.whl |
|---|---|
| Size | 34.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
ae5f46572e961961fde06271eb4a8aeecac265e292983eec092c00edea64fe64
|
|
BLAKE2b-256 checksum How to use checksums |
b7aa91af5167aac01949068750e8932ec6f05fb57d42362c35ac4849e46ee19d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.10.9
|
Security for django-phone-verify 3.3.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.