Django : How To Implement Token Authentication In Django And Django Rest Framework

Feb 18 2023 . 5 min read

Token Authentication is one of the built-in authentication system in Django Rest Framework. Token Authentication is an one time token that is generate for every newly created users, which is unique and static.

Let's Setup Token Authentication

To setup Token Authentication, just follow these steps :


  1. To use Token Authentication, you need to add 'rest_framework.authtoken' in INSTALLED_APPS
    settings.py
    1. INSTALLED_APPS = [
    2.    ...
    3.    'rest_framework.authtoken'
    4.    ...
    5. ]

  2. Now your django project must be configured to use the library. In settings.py, add the authentication classes:
    settings.py
    1. REST_FRAMEWORK = [
    2.    ...
    3.    'DEFAULT_AUTHENTICATION_CLASSES': (
    4.      ...
    5.       'rest_framework.authentication.TokenAuthentication'
    6.      ...
    7.      )
    8.    ...
    9. ]

Agenda

We are going to create three API's here :


  1. Signup Api - That will create an user.

  2. Login Api - That will generate a access and refresh token for authorised user.

  3. Student Api - That will show the student data using the access token.

1. Signup API

To create a signup API, please follow these steps :


Create a serializers.py file within your app level. Let's create a ModelSerializer for Signup.

serializers.py
  1. from rest_framework import serializers
  2. from django.contrib.auth.models import User
  3. from django.contrib.auth.hashers import make_password
  4. class SignupSerializer(serializers.ModelSerializer):
  5.     """override create method to change the password into hash."""
  6.     def create(self, validated_data):
  7.             validated_data["password"] = make_password(validated_data.get("password"))
  8.             return super(SignupSerializer, self).create(validated_data)
  9.     class Meta:
  10.             model = User
  11.             fields = ['username','password']

Here in SignupSerializer class we have override the create method and convert our string password into hash using make_password() function.



Next open a views.py file, and Let's create a APIView class for Signup.

views.py
  1. from rest_framework.views import APIView
  2. from django.contrib.auth.models import User
  3. from rest_framework.response import Response
  4. from rest_framework import status
  5. from .serializers import SignupSerializer
  6. class SignupAPIView(APIView):
  7.     """This api will handle signup"""
  8.     def post(self,request):
  9.             serializer = SignupSerializer(data = request.data)
  10.             if serializer.is_valid():
  11.                     """If the validation success, it will created a new user."""
  12.                     serializer.save()
  13.                     res = { 'status' : status.HTTP_201_CREATED }
  14.                     return Response(res, status = status.HTTP_201_CREATED)
  15.            res = { 'status' : status.HTTP_400_BAD_REQUEST, 'data' : serializer.errors }
  16.            return Response(res, status = status.HTTP_400_BAD_REQUEST)


Next open an urls.py file and let's create an endpoint for signup api.

urls.py
  1. from django.urls import path
  2. from . import views
  3. urlspatterns = [
  4.     path("api/user/signup/", views.SignupAPIView.as_view(), name="user-signup"),
  5.   ]


Create a signals.py file and here we are going to create token by using signals.

signals.py
  1. from django.conf import settings
  2. from django.db.models.signals import post_save
  3. from django.dispatch import receiver
  4. from rest_framework.authtoken.models import Token
  5. @receiver(post_save, sender=settings.AUTH_USER_MODEL)
  6. def create_auth_token(sender, instance=None, created=False, **kwargs):
  7.         if created:
  8.                 Token.objects.create(user=instance)

By generating token using signals is the best way. So here we actually use post_save signals, that will create a token, when new user will create.

2. Login API

Now we will going to create a Login Api that will basically generate an token, so that we can use this token to access the students data.


To create a login api, follow these steps :


Open a serializers.py file and let's create a ModelSerializer for Login.

serializers.py
  1. from rest_framework import serializers
  2. from django.contrib.auth.models import User
  3. from django.contrib.auth.hashers import make_password
  4. class LoginSerializer(serializers.ModelSerializer):
  5.     username = serializers.CharField()
  6.     class Meta:
  7.             model = User
  8.             fields = ['username','password']


Next, open a views.py file, and Let's create a APIView class for Login.

views.py
  1. from rest_framework.views import APIView
  2. from django.contrib.auth.models import User
  3. from rest_framework.response import Response
  4. from rest_framework import status
  5. from .serializers import LoginSerializer
  6. from rest_framework.authtoken.models import Token
  7. from django.contrib.auth import authenticate
  8. class LoginAPIView(APIView):
  9.     """This api will handle login and return token for authenticate user."""
  10.     def post(self,request):
  11.             serializer = LoginSerializer(data = request.data)
  12.             if serializer.is_valid():
  13.                     username = serializer.validated_data["username"]
  14.                     password = serializer.validated_data["password"]
  15.                     user = authenticate(request, username=username, password=password)
  16.                     if user is not None:
  17.                         """We are reterving the token for authenticated user."""
  18.                         token = Token.objects.get(user=user)
  19.                         response = {
  20.                                "status": status.HTTP_200_OK,
  21.                                "message": "success",
  22.                                "data": {
  23.                                        "Token" : token.key
  24.                                        }
  25.                                }
  26.                         return Response(response, status = status.HTTP_200_OK)
  27.                     else :
  28.                         response = {
  29.                                "status": status.HTTP_401_UNAUTHORIZED,
  30.                                "message": "Invalid Email or Password",
  31.                                }
  32.                         return Response(response, status = status.HTTP_401_UNAUTHORIZED)
  33.             response = {
  34.                  "status": status.HTTP_400_BAD_REQUEST,
  35.                  "message": "bad request",
  36.                  "data": serializer.errors
  37.                  }
  38.             return Response(response, status = status.HTTP_400_BAD_REQUEST)


Next, open an urls.py file and let's create an endpoint for login api.

urls.py
  1. from django.urls import path
  2. from . import views
  3. urlspatterns = [
  4.     path("api/user/login/", views.LoginAPIView.as_view(), name="user-login"),
  5.   ]

3. Students Api

Now we will going to create our Students Api that will basically return students data.


Open a models.py file and let's define student model.

models.py
  1. from django.db import models
  2. class Student(models.Model):
  3.        name = models.CharField(max_length = 100)
  4.        email = models.EmailField(max_length = 277)
  5.        created_at = models.DateTimeField(auto_now_add = True, null = True)
  6.        updated_at = models.DateTimeField(auto_now_add = True, null = True)
  7.        def __str__(self):
  8.               return str(self.name)


Hit these commands to create student table.

python manage.py makemigrations
python manage.py migrate


Next open a serializers.py file and let's create a ModelSerializer for Student.

serializers.py
  1. from rest_framework import serializers
  2. from .models import Student
  3. class StudentSerializer(serializers.ModelSerializer):
  4.     class Meta:
  5.             model = Student
  6.             fields = ['name','email','created_at','updated_at']


Next, open a views.py file, and Let's create a APIView class for Student.

views.py
  1. from rest_framework.views import APIView
  2. from rest_framework.response import Response
  3. from rest_framework import status
  4. from .serializers import StudentSerializer
  5. from .models import Student
  6. from rest_framework.permissions import IsAuthenticated
  7. class StudentAPIView(APIView):
  8.     """This api will handle student"""
  9.     permission_classes = [ IsAuthenticated ]
  10.     def get(self,request):
  11.             data = Student.objects.all()
  12.             serializer = StudentSerializer(data, many = True)
  13.             response = {
  14.                    "status": status.HTTP_200_OK,
  15.                    "message": "success",
  16.                    "data": serializer.data
  17.                    }
  18.             return Response(response, status = status.HTTP_200_OK)

We have to must add the IsAuthenticated permission to our student api. It means to get the students data, ideally you need to pass the access token, that you got at the time of login.



Next, open an urls.py file and let's create an endpoint for student api.

urls.py
  1. from django.urls import path
  2. from . import views
  3. urlspatterns = [
  4.     path("api/students/", views.StudentAPIView.as_view(), name="api-student"),
  5.   ]

Conclusion

This is how you can secure your api's using Token Authentication, just you need to only add IsAuthenticated to permission_classes, and set the TokenAuthentication to authenticate_classess in settings file.