Skip to content

๐Ÿงจ one time passwords

One time password(OTP) functionality allows you not to store passwords in your databases. It lets to generate passwords valid for a certain amount of time and usable only once. It uses redis to store and retrieve one time passwords.

Email and Phone OTP

OTP models

OTP models are almost the same as other swap models. The key difference is that they don't have password fields.

Email and Phone OTP

To use specified model with OTP functionality follow the steps below.

Step 1 - change INSTALLED_APPS

Add the following apps below to INSTALLED_APPS in order to swap to the specified OTP model.

"swap_user",
"swap_user.to_email_otp",
"swap_user",
"swap_user.to_phone_otp",

Step 2 - set AUTH_USER_MODEL

AUTH_USER_MODEL = "swap_to_email_otp.EmailOTPUser"
AUTH_USER_MODEL = "swap_to_phone_otp.PhoneOTPUser"

Step 3 - replace django.contrib.admin

In order to render django admin pages properly with one time password login enabled you should replace django.contrib.admin in your INSTALLED_APPS to the one below:

"swap_user.apps.OTPSiteConfig",
"swap_user.apps.OTPSiteConfig",

Step 4 - apply migrations

python manage.py migrate swap_to_email
python manage.py migrate swap_to_phone

Step 4 - install redis cache libraries

pip install django-redis redis
pip install redis

Step 5 - set redis as cache in settings

CACHES = {
    "default": {
        "BACKEND": "django_redis.cache.RedisCache",
        "LOCATION": "redis://127.0.0.1:6379/1",
        "OPTIONS": {
            "CLIENT_CLASS": "django_redis.client.DefaultClient",
        }
    }
}
CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.redis.RedisCache',
        'LOCATION': 'redis://127.0.0.1:6379',
    }
}

Step 6 - set sender class

SWAP_USER = {
    "OTP_SENDER_CLASS": "swap_user.otp.senders.EmailOTPSender",
}
# For phones otp you need to define your own sender class
# sender.py
from swap_user.otp.senders import AbstractOTPSender

class MyPhoneOTPSender(AbstractOTPSender):

    def send(self, receiver: str, otp: str, **kwargs):
        # implement your logic here.
        # For example, interaction with sms/push API.
        pass

...
# settings.py
SWAP_USER = {
    "OTP_SENDER_CLASS": "<path_to_your_sender_class>",
}

Email OTP showcase - login into the admin

Custom sender class

By sender we mean class that sends your one time password over a specified transprot(using email, sms, push, etc). You can implement any custom sender class and use this as your transport backend.

Example is shown below.

from swap_user.otp.senders import AbstractOTPSender


class PushNotificationsOTPSender(AbstractOTPSender):
    """
    Sending code over push.
    """

    def send(self, receiver: str, otp: str, **kwargs):
        PushAPI.send(to=receiver, title='Use this code', text=otp)

Then include your class path into the settings:

# settings.py
SWAP_USER = {
    "OTP_SENDER_CLASS": "<path_to_your_sender_class>",
}