Skip to main content

A Django app to supports 2FA(Two Factor Authentication) on djangorestframework.

Project description

Django DRF OTP

Django DRF OTP enables otp authorization. This module depends on Django Rest Framework module.

Installation

Add django_drf_otp and requirements to your INSTALLED_APPS setting.

INSTALLED_APPS = [
    ...,
    "rest_framework", # Requirement
    "rest_framework.authtoken", # Requirement
    "django_drf_otp",
    ...
]

If you're intending to use the base auth API you'll probably also want to add Django DRF OTP's login and logout views. Add the following to your root urls.py file.

urlpatterns = [
    ...,
    path("api-auth/", include("django_drf_otp.urls")),
    ...
]

Django DRF OTP provides two endpoints login/ and verify-token/:

  • login: Validates user with given USERNAME_FIELD and password. By the default returns a success message.

  • verify-token: Validates the otp token with given token. By the default returns a token (from Rest Framework's Token[link] model).

And finally run python manage.py migrate to create models.

Contents

Settings

Configuration for Django DRF OTP is all namespaced inside a single Django setting, named OTP_SETTINGS.

For example your project's settings.py file might include something like this:

OTP_SETTINGS = {
    "ENABLE_OTP_AUTHENTICATION": True,
}

Accessing settings

If you need to access the values of REST framework's API settings in your project, you should use the api_settings object. For example.

from django_drf_otp.settings import otp_settings

print(api_settings.ENABLE_OTP_AUTHORIZATION)

API Reference

API policy settings

The following settings control the basic API policies.

ENABLE_OTP_AUTHENTICATION

Enables or Disables OTP Authorization.

Default: True

TOKEN_LENGTH

The default token length to use for otp token creation.

Default: True

TOKEN_SECRET

The default token creation secret characters.

Default: 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567'

DEFAULT_TOKEN_TYPE

The default token type to use for otp token creation.

Default: TOTP

TOTP_TOKEN_TTL

The default otp token ttl value.

Default: 300

EMAIL_CONFIG

A dict of email config that used by otp email template.

Default:

{
    "SUBJECT": _("Verification Token"),
    "TEMPLATE_PATH": "django_drf_otp/email.html",
}
  • SUBJECT: Subject of email.
  • TEMPLATE_PATH: The template used for email body.

ViewSets

OTPTokenViewSet

The OTPTokenViewSet class inherits from Rest Framework's GenericViewSet(link). This viewset provides actions: login, verify_token and provides methods: get_success_response_data, get_extra_context_data.

from rest_framework import viewsets
from django_drf_otp.services import OTPService
from django_drf_otp.serializers import OTPTokenSerializer, OTPTokenVerifySerializer


class OTPTokenViewSet(viewsets.GenericViewSet):
    permission_classes = (AllowAny,)
    serializer_classes = {
        "login": OTPTokenSerializer,
        "verify_token": OTPTokenVerifySerializer,
    }

    def __init__(self, **kwargs: Any) -> None:
        super().__init__(**kwargs)

        self.OTP_ENABLED = otp_settings.ENABLE_OTP_AUTHENTICATION

    def login(self, request: Request, *args, **kwargs):
        ...

    def verify_token(self, request: Request, *args, **kwargs):
        ...

    def get_serializer_class(self, *args, **kwargs) -> Type[serializers.Serializer]:
        ...

    def get_success_response_data(self, validated_data: Dict, **kwargs) -> Dict:
        ...

    def get_extra_context_data(self, request: Request, validated_data: Dict) -> Dict:
        ...

API attributes

permission_classes

A tuple. Rest Framework's permission_classes[link] attribute.

Default:

permission_classes = (AllowAny,)

serializer_classes

A dict contains the action&serializer pair. This attribute used by get_serializer_class[link] that returns a serializer according to action[link].

Default:

serializer_classes = {
    "login": OTPTokenSerializer,
    "verify_token": OTPTokenVerifySerializer,
}

API actions&methods

login

This action validates the user and send a token based on the user's notification preference(Currently only email available) if ENABLE_OTP_AUTHENTICATION is True, otherwise a token[link]. By the default uses OTPTokenSerializer for validation.

verify_token

This action validates the otp token and returns a token[link] if ENABLE_OTP_AUTHENTICATION is True, otherwise a error message. By the default uses OTPTokenVerifySerializer for validation.

💡 Note: If you want to change validation serializer class edit get_serializer_class method or serializer_classes attribute. For editing responses see get_success_response_data.

get_serializer_class

This method is used to decide the serializer class and returns a serializer class. By the default returns a serializer defined in serializer_classes with the action[link]

Default:

def get_serializer_class(self, *args, **kwargs) -> Type[serializers.Serializer]:
    return self.serializer_classes[self.action]

get_success_response_data

This method is used to decide the response data to return to the user. Takes the serializer's validated data is returned by get_serializer_class and returns a dict. By the default returns the success message({"message": _("OTP token sent successfully.")}), othervise Rest Framework's token({"token": token.key}).

⚠️ Warning: If you are not override get_success_response_data and get_extra_context_data, you must provide User object with user key in your serializer's validated_data

get_extra_context_data

This method is returns data used by notifiers. By the default returns a dict contains request object and user's first_name, last_name and full_name.

Example

from django_drf_otp.viewsets import OTPTokenViewSet
from django_drf_otp.settings import otp_settings
from .serializers import CustomLoginSerializer, CustomTokenVerifySerializer

class LoginViewSet(OTPTokenViewSet):
    def get_serializer_class(self, *args, **kwargs) -> Type[serializers.Serializer]:
        if self.action == "login":
            return CustomLoginSerializer
        else:
            return CustomTokenVerifySerializer

    def get_success_response_data(self, validated_data: Dict, **kwargs) -> Dict:
        if self.action == "login" and otp_settings.ENABLE_OTP_AUTHENTICATION:
            return validated_data
        else:
            token,
            return {"token":}

Strategies

Strategies are used to generate otp tokens with different token algorithms (only TOTP tokens are available for now). This module uses pyotp module for a token creation.

Class's attributes

token_type

A string attribute. It can be one of the values defined in TokenType(defined in django_drf_otp.enums).

API methods

generate_token

A abstract method. This method used to create a otp token. Returns token string. If you want to implement a new strategy, must be overrided.

Default (in BaseOTPStrategy):

@abstractmethod
def generate_token(self, extra_secret_chars: Optional[str] = None) -> str:
    NotImplementedError()

verify_token

This method used to verify a otp token. Returns True if the token is verified, otherwise False. if you want to implement a new strategy, must be overrided.

Default (in BaseOTPStrategy):

@abstractmethod
def verify_token(self, token: str, extra_secret_chars: Optional[str] = None) -> bool:
    NotImplementedError()

generate_token_for_user

A abstract method. This method used to create a otp token for a user via VerificationToken(defined in django_drf_otp.models). If you want to implement a new strategy, must be overrided.

Default (in BaseOTPStrategy):

@abstractmethod
def generate_token_for_user(self, user: AbstractUser) -> VerificationToken:
    NotImplementedError()

create_verification_token

A static method. This method used to create a VerificationToken model instance for user.

Default (in BaseOTPStrategy):

@staticmethod
def create_verification_token(
    user: AbstractUser, token: str,
    token_type: TokenType,
    secret_chars: str,
) -> VerificationToken:
    return VerificationToken.objects.create(
        user=user,
        token=token,
        token_type=token_type,
        secret_chars=secret_chars
    )

deactivate_old_verification_tokens

A static method. This method used to deactivates user's all VerificationToken instances excluding given token instance.

Default (in BaseOTPStrategy):

@staticmethod
def deactivate_old_verification_tokens(
    verification_token: VerificationToken
) -> None:
    VerificationToken.objects.filter(user=verification_token.user, is_active=True).exclude(
        id=verification_token.id
    ).update(is_active=False)

Example

You can easily implement a new strategy for your special solutions (with only defined token_types in TokenType class).

Then create a new strategy class:

class CustomTOTPStrategy(BaseOTPStrategy):
    token_type = TokenType.TOTP

    def generate_token(self, extra_secret_chars: Optional[str] = None) -> str:
        # <Your code here>

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

django-drf-otp-0.0.9.tar.gz (18.4 kB view hashes)

Uploaded Source

Built Distribution

django_drf_otp-0.0.9-py3-none-any.whl (22.5 kB view hashes)

Uploaded Python 3

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page