DEV Community

Cover image for JWT Custom Authentication for Django Application
chryzcode
chryzcode

Posted on

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

        # drf_auth_proj/seetings.py
        
        from datetime import timedelta
        
        # Read more abou this on oficial docs
        # https://django-rest-framework-simplejwt.readthedocs.io/en/latest/settings.html
        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",
        
            #JWT TOKEN CUSTOM(in drf_app.views.py)
            "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.

Image description

  • 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).

Image description

  • 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.

Image description

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😉.

Top comments (0)