Django Rest Framework Custom JWT Authentication Backend

JWT Implementation for DRF with Phone Number

4 min readFeb 4, 2023


Hi folks. In this text, I am going to write about how we can implement custom backend in our Django applications and implement JWT. I had a task for one of my freelance jobs to provide functionality for log-in with phone number or username.

Photo by Kelly Sikkema on Unsplash


Firstly, we are going to create our own User model. Then we will create a class to extend BaseAuthentication class. This custom authentication class will be used by IsAuthenticated permission. Also, we will need an APIView to obtain/generate JWT tokens which we call it ObtainTokenView .

Also, I am not going to demonstrate step by step the easiest steps like how to create a project etc. I will be showing the examples on the project that I created for my test.

Custom User Model

I created a User model which is inherited AbstractUser model.

# apps/management/

from django.contrib.auth.models import AbstractUser
from django.db import models

class User(AbstractUser):
MALE = 'Male'
FEMALE = 'Female'
(MALE, 'Male'),
(FEMALE, 'Female'),
phone_number = models.CharField(max_length=20, blank=True, null=True, unique=True)
gender = models.CharField(max_length=6, choices=GENDER_IN_CHOICES, null=True, blank=True)
country = models.CharField(max_length=120, null=True, blank=True)
city = models.CharField(max_length=120, null=True, blank=True)
state = models.CharField(max_length=120, null=True, blank=True)
is_approved_to_be_in_touch = models.BooleanField(default=False)

Now we need to set default User model in our file.


# ...

# custom user model
AUTH_USER_MODEL = "management.User"

# ...

If we need to use User class to use ORM methods etc. we should use get_user_model function.

# any file that needs to use User model

from django.contrib.auth import get_user_model

User = get_user_model()

You can check the documentation below to read something official.

Custom Authentication Backend

We can think that the class below will be used when the app get a request that is need to be authenticated for checking user is authenticated or not. The class below check HTTP_AUTHORIZATION header of request for extracting the token.

The logic in our authentication mechanism is to check is there a user with the username in request body. If there is no user with username, class will filter users by using their phone_number .

It would be nice to remind that the class will be used to check does request have a JWT or not.

# apps/management/

from datetime import datetime, timedelta

import jwt
from django.conf import settings
from django.contrib.auth import get_user_model
from rest_framework import authentication
from rest_framework.exceptions import AuthenticationFailed, ParseError

User = get_user_model()

class JWTAuthentication(authentication.BaseAuthentication):
def authenticate(self, request):
# Extract the JWT from the Authorization header
jwt_token = request.META.get('HTTP_AUTHORIZATION')
if jwt_token is None:
return None

jwt_token = JWTAuthentication.get_the_token_from_header(jwt_token) # clean the token

# Decode the JWT and verify its signature
payload = jwt.decode(jwt_token, settings.SECRET_KEY, algorithms=['HS256'])
except jwt.exceptions.InvalidSignatureError:
raise AuthenticationFailed('Invalid signature')
raise ParseError()

# Get the user from the database
username_or_phone_number = payload.get('user_identifier')
if username_or_phone_number is None:
raise AuthenticationFailed('User identifier not found in JWT')

user = User.objects.filter(username=username_or_phone_number).first()
if user is None:
user = User.objects.filter(phone_number=username_or_phone_number).first()
if user is None:
raise AuthenticationFailed('User not found')

# Return the user and token payload
return user, payload

def authenticate_header(self, request):
return 'Bearer'

def create_jwt(cls, user):
# Create the JWT payload
payload = {
'user_identifier': user.username,
'exp': int(( + timedelta(hours=settings.JWT_CONF['TOKEN_LIFETIME_HOURS'])).timestamp()),
# set the expiration time for 5 hour from now
'username': user.username,
'phone_number': user.phone_number

# Encode the JWT with your secret key
jwt_token = jwt.encode(payload, settings.SECRET_KEY, algorithm='HS256')

return jwt_token

def get_the_token_from_header(cls, token):
token = token.replace('Bearer', '').replace(' ', '') # clean the token
return token

To activate our authentication class we need to set it as a default authentication class of rest framework.


# ...


# ...

You can check the link below to learn more about BaseAuthentication class.

Obtain Token API Serializer

We will use a simple serializer for our login view.

# apps/management/api/

from rest_framework import serializers

class ObtainTokenSerializer(serializers.Serializer):
username = serializers.CharField()
password = serializers.CharField()

Obtain Token API View

The view below will be used to generate JWT token. We try to get user instance by using username or phone_number.

from django.contrib.auth import get_user_model
from rest_framework import views, permissions, status
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response

from import ObtainTokenSerializer
from import UserSerializer
from import JWTAuthentication

User = get_user_model()

class ObtainTokenView(views.APIView):
permission_classes = [permissions.AllowAny]
serializer_class = ObtainTokenSerializer

def post(self, request, *args, **kwargs):
serializer = self.serializer_class(

username_or_phone_number = serializer.validated_data.get('username')
password = serializer.validated_data.get('password')

user = User.objects.filter(username=username_or_phone_number).first()
if user is None:
user = User.objects.filter(phone_number=username_or_phone_number).first()

if user is None or not user.check_password(password):
return Response({'message': 'Invalid credentials'}, status=status.HTTP_400_BAD_REQUEST)

# Generate the JWT token
jwt_token = JWTAuthentication.create_jwt(user)

return Response({'token': jwt_token})

Test The View

We see the successfull login attempts below.

Image by Author | Login via phone number
Image by Author | Login via username

Now you can use the token in Authorization header of request.



We have successfully created our own Authentication Backend for providing functionality to be logged-in via username (email) or phone number. Hopefully, it was helpful for you. I know it is a bit short but I do not think that it is necessary to write unnecessary descriptions just for making it long. Especially in the age that we have AI boosted tools.

Kind regards



Writer for

Lifelong learner & Developer. I use technology that helps me.