Skip to main content
https://github.com/CuriousLearner/django-phone-verify/actions/workflows/main.yml/badge.svg?branch=master https://coveralls.io/repos/github/CuriousLearner/django-phone-verify/badge.svg?branch=master License https://static.pepy.tech/badge/django-phone-verify?period=total&units=international_system&left_color=black&right_color=darkgreen&left_text=Downloads https://img.shields.io/badge/Made%20with-Python-1f425f.svg https://img.shields.io/badge/Maintained%3F-yes-green.svg https://badge.fury.io/py/django-phone-verify.svg https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square

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:

  1. Send Verification Code - User requests verification, receives SMS with security code

  2. Verify Code - User submits code, system validates and confirms phone number

  3. Session Management - Secure JWT-based session tokens prevent tampering

  4. 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

  1. Add phone_verify to INSTALLED_APPS:

INSTALLED_APPS = [
    ...
    "phone_verify",
    ...
]
  1. Run migrations:

python manage.py migrate
  1. Include the API URLs in your project’s urls.py:

from django.urls import path, include

urlpatterns = [
    ...
    path("api/phone/", include("phone_verify.urls")),
    ...
]
  1. 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:

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:

  1. 🐛 Report bugs via GitHub Issues

  2. 💡 Suggest features or improvements

  3. 🔧 Submit pull requests - please check the contributing guide first

  4. 📖 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)

Source distribution for django-phone-verify 3.3.0
File Size Uploaded Provenance
django_phone_verify-3.3.0.tar.gz 9.7 MB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for django-phone-verify 3.3.0
File Interpreter ABI Platform
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.

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