JWT Custom Authentication for Django Application

JWT Custom Authentication for Django Application

Introduction

What is the good of a web application without an efficient authentication system?

In this article, I will share how to create a simple and effective authentication for your Django web application.

By default, Django uses the built-in basic authentication system, i.e. (using an email/ username and password to log in directly) how efficient can this be with an Application Programming Interface(API) without tokens for authentication?

Introducing Simple JSON Web Token (JWT) it provides a JSON Web Token authentication backend for a Django REST Framework application.

Let's start building

  • Create Django Application

    Navigate to the directory of your choice on the terminal and create your Django application.

      cd desktop # navigated to the desktop directory (windows)
      django-admin --version # check if django is installed
      django-admin startproject drf_auth_proj # create django project
      cd drf_auth_proj # naviage to the project directory
      django-admin startapp drf_app # create a django application
    
  • Create a Virtual Environment(optional)

      virtualenv venv # created a virtual environment named venv
      venv\Scripts\activate # activate virtual environment (windows)
    
  • Install Necessary Dependencies

      pip install djangorestframework # install drf(installs django by default)
      pip install djangorestframework-simplejwt # install simple jwt
      # add dependencies to requirements.txt file
      pip freeze > requirements.txt #make sure the virtulal environment is activated
    
  • Application Configuration

    We are adding some configurations in the settings.py file(Django app, dependencies).

      #settings.py
      INSTALLED_APPS = [
          # add 
          'drf_app', # django application
          'rest_framework', # django rest framework
          'rest_framework_simplejwt.token_blacklist', #(JWT BLACKLIST CONFIG)
      ]
    
      # set simple JWT to default authentication
      REST_FRAMEWORK = {
          'DEFAULT_AUTHENTICATION_CLASSES': (
              'rest_framework_simplejwt.authentication.JWTAuthentication',
          )
      }
    
  • Create a URL file in the application directory(drf_app)

      #drf_app/urls.py
      from django.urls import path
      from rest_framework_simplejwt.views import (
          TokenObtainPairView,
          TokenRefreshView,
      ) # import views from JWT 
    
      urlpatterns =  [
          #JWT
          path('token/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
          path('token/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
      ]
    
  • Add the application URL to the project URL file

      # drf_auth_proj/urls.py
      from django.urls import path, include # import include
      urlpatterns = [
    
          path('api/v1/', include('drf_app.urls')), #add app urls file
      ]
    
  • Create customized token-obtain serializer(optional)

    This is to add more data/information to a token. The code below adds/encrypts a user's email, and first and last name to the token.

      # drf_app/views.py
    
      from rest_framework_simplejwt.serializers import TokenObtainPairSerializer
    
      class MyTokenObtainPairSerializer(TokenObtainPairSerializer):
          @classmethod
          def get_token(cls, user):
              token = super().get_token(user)
    
              # Add custom claims based on your user model fields
              token['email'] = user.email
              token['username'] = user.username
              # token['first_name'] = user.first_name
              # token['last_name'] = user.last_name
              return token
    
  • More JWT configurations

    
      from datetime import timedelta
    
      SIMPLE_JWT = {
          "ACCESS_TOKEN_LIFETIME": timedelta(minutes=5), 
          "REFRESH_TOKEN_LIFETIME": timedelta(days=30),
          "ROTATE_REFRESH_TOKENS": True,
          "BLACKLIST_AFTER_ROTATION": True,
          "UPDATE_LAST_LOGIN": False,
    
          "ALGORITHM": "HS256",
          "VERIFYING_KEY": "",
          "AUDIENCE": None,
          "ISSUER": None,
          "JSON_ENCODER": None,
          "JWK_URL": None,
          "LEEWAY": 0,
    
          "AUTH_HEADER_TYPES": ("Bearer",),
          "AUTH_HEADER_NAME": "HTTP_AUTHORIZATION",
          "USER_ID_FIELD": "id",
          "USER_ID_CLAIM": "user_id",
          "USER_AUTHENTICATION_RULE": 
           "rest_framework_simplejwt.authentication.default_user_authentication_rule",
    
          "AUTH_TOKEN_CLASSES": ("rest_framework_simplejwt.tokens.AccessToken",),
          "TOKEN_TYPE_CLAIM": "token_type",
          "TOKEN_USER_CLASS": "rest_framework_simplejwt.models.TokenUser",
    
          "JTI_CLAIM": "jti",
    
          "SLIDING_TOKEN_REFRESH_EXP_CLAIM": "refresh_exp",
          "SLIDING_TOKEN_LIFETIME": timedelta(minutes=5),
          "SLIDING_TOKEN_REFRESH_LIFETIME": timedelta(days=1),
    
          "TOKEN_OBTAIN_SERIALIZER": 
         "rest_framework_simplejwt.serializers.TokenObtainPairSerializer",
          "TOKEN_REFRESH_SERIALIZER": 
          "rest_framework_simplejwt.serializers.TokenRefreshSerializer",
          "TOKEN_VERIFY_SERIALIZER": 
          "rest_framework_simplejwt.serializers.TokenVerifySerializer",
          "TOKEN_BLACKLIST_SERIALIZER": 
           "rest_framework_simplejwt.serializers.TokenBlacklistSerializer",
          "SLIDING_TOKEN_OBTAIN_SERIALIZER": 
         "rest_framework_simplejwt.serializers.TokenObtainSlidingSerializer",
          "SLIDING_TOKEN_REFRESH_SERIALIZER": 
         "rest_framework_simplejwt.serializers.TokenRefreshSlidingSerializer",
          "TOKEN_OBTAIN_SERIALIZER": "drf_app.views.MyTokenObtainPairSerializer", }
    
  • Migrate the changes to the database

      # on the terminal
      python manage.py migrate
    
  • Create Super User

      python manage.py createsuperuser
    
  • Check the Admin Page (optional)

    If you can remember, we did some token blacklist configuration. It saves all tokens generated and makes sure it is used only once.

  • Generate Token

    Make sure the server is running python manage.py runserver. Then, open the Token Obtain Pair URL on a browser and enter the necessary details(username and password).

    • Decode the Token Generated

      Visit the JSON Web Token website https://jwt.io/ and paste any of your tokens there. The email and username field in the image below results from the custom Token Obtain Pair Serializer views.


      Here is the link to the project's repository for reference sake.

      Conclusion

      I hope you found the article helpful and created a JWT authentication for your Django application.

      If yes, do well to like and share this piece and comment with me on Linkedin, Twitter and GitHub. And if you like what you read and want to show support, you can buy me coffee😉.