Published in


Django Rest Framework Custom JWT Authentication Backend

JWT Implementation for DRF with Phone Number

Photo by Kelly Sikkema on Unsplash


Custom User 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)

# ...

# custom user model
AUTH_USER_MODEL = "management.User"

# ...
# any file that needs to use User model

from django.contrib.auth import get_user_model

User = get_user_model()

Custom Authentication Backend

# 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

# ...


# ...

Obtain Token API Serializer

# apps/management/api/

from rest_framework import serializers

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

Obtain Token API View

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

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




Everything connected with Tech & Code. Follow to join our 1M+ monthly readers

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store

Lifelong learner & Freelancer. I use technology that helps me. I’m currently working as a Business Intelligence & Backend Developer.