django-phone-verify
allows you to plug in your own SMS backend by extending the base backend interface.
This lets you use any third-party service such as AWS SNS, MessageBird, Plivo, etc.
This guide walks you through creating:
- A custom SMS backend (example: Nexmo)
- A sandbox version for testing
This example demonstrates how to integrate Nexmo. The same pattern applies to any other provider.
Create a new Python file in your Django project, e.g., nexmo.py
.
Update your settings.py
:
PHONE_VERIFICATION = {
'BACKEND': 'nexmo.NexmoBackend',
'OPTIONS': {
'KEY': 'Fake Key',
'SECRET': 'Fake Secret',
'FROM': '+1234567890',
'SANDBOX_TOKEN': '123456',
},
'TOKEN_LENGTH': 6,
'MESSAGE': 'Welcome to {app}! Please use security code {security_code} to proceed.',
'APP_NAME': 'Phone Verify',
'SECURITY_CODE_EXPIRATION_TIME': 3600,
'VERIFY_SECURITY_CODE_ONLY_ONCE': True,
}
Note
You can use an official client library like nexmo
, or make raw API calls.
import nexmo
from phone_verify.backends.base import BaseBackend
class NexmoBackend(BaseBackend):
def __init__(self, **options):
super().__init__(**options)
options = {key.lower(): value for key, value in options.items()}
self._key = options.get("key")
self._secret = options.get("secret")
self._from = options.get("from")
self.client = nexmo.Client(key=self._key, secret=self._secret)
def send_sms(self, number, message):
self.client.send_message({
'from': self._from,
'to': number,
'text': message,
})
def generate_message(self, security_code, context=None):
"""You can optionally override the message formatting by
defining a `generate_message()` method in your backend.
This method receives the `security_code` and an optional
`context` dictionary passed at runtime, giving you more
flexibility than using a static `MESSAGE` template."""
username = context.get("username", "User") if context else "User"
return f"Hi {username}, your OTP is {security_code}."
def send_bulk_sms(self, numbers, message):
for number in numbers:
self.send_sms(number, message)
A sandbox backend is useful for testing flows without sending real SMS messages.
import nexmo
from phone_verify.backends.base import BaseBackend
from phone_verify.models import SMSVerification
class NexmoSandboxBackend(BaseBackend):
def __init__(self, **options):
super().__init__(**options)
options = {key.lower(): value for key, value in options.items()}
self._key = options.get("key")
self._secret = options.get("secret")
self._from = options.get("from")
self._token = options.get("sandbox_token")
self.client = nexmo.Client(key=self._key, secret=self._secret)
def send_sms(self, number, message):
self.client.send_message({
'from': self._from,
'to': number,
'text': message,
})
def generate_message(self, security_code, context=None):
return f"[SANDBOX] Your code is {security_code}"
def send_bulk_sms(self, numbers, message):
for number in numbers:
self.send_sms(number, message)
def generate_security_code(self):
return self._token
def validate_security_code(self, security_code, phone_number, session_token):
return SMSVerification.objects.none(), self.SECURITY_CODE_VALID
Note
generate_security_code
returns a constant token for predictable testing.validate_security_code
always treats the token as valid.
PHONE_VERIFICATION = {
'BACKEND': 'nexmo.NexmoSandboxBackend',
'OPTIONS': {
'KEY': 'Fake Key',
'SECRET': 'Fake Secret',
'FROM': '+1234567890',
'SANDBOX_TOKEN': '123456',
},
'TOKEN_LENGTH': 6,
'MESSAGE': 'Welcome to {app}! Please use security code {security_code} to proceed.',
'APP_NAME': 'Phone Verify',
'SECURITY_CODE_EXPIRATION_TIME': 3600,
'VERIFY_SECURITY_CODE_ONLY_ONCE': True,
}
You’re now ready to use your own backend with django-phone-verify
.
In production, configure the BACKEND
setting to point to your real backend class.