{"id":25287549,"url":"https://github.com/mrshakil015/django-jwt-api-token-authentication","last_synced_at":"2026-05-02T19:31:34.424Z","repository":{"id":274065009,"uuid":"921785252","full_name":"mrshakil015/Django-JWT-API-Token-Authentication","owner":"mrshakil015","description":"In this project, I configure how to apply JWT API token and also Email based OTP authentication with Django Rest Framework.","archived":false,"fork":false,"pushed_at":"2025-01-28T17:31:06.000Z","size":72,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-04-06T17:15:12.268Z","etag":null,"topics":["django","email-otp-validation","otp-verification","rest-framework","rest-framework-simplejwt"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mrshakil015.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2025-01-24T16:02:14.000Z","updated_at":"2025-01-28T17:31:09.000Z","dependencies_parsed_at":"2025-01-24T17:40:27.937Z","dependency_job_id":null,"html_url":"https://github.com/mrshakil015/Django-JWT-API-Token-Authentication","commit_stats":null,"previous_names":["mrshakil015/django-jwt-api-token-authentication"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/mrshakil015/Django-JWT-API-Token-Authentication","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mrshakil015%2FDjango-JWT-API-Token-Authentication","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mrshakil015%2FDjango-JWT-API-Token-Authentication/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mrshakil015%2FDjango-JWT-API-Token-Authentication/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mrshakil015%2FDjango-JWT-API-Token-Authentication/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mrshakil015","download_url":"https://codeload.github.com/mrshakil015/Django-JWT-API-Token-Authentication/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mrshakil015%2FDjango-JWT-API-Token-Authentication/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32547645,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-02T19:18:06.202Z","status":"ssl_error","status_checked_at":"2026-05-02T19:16:21.335Z","response_time":132,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["django","email-otp-validation","otp-verification","rest-framework","rest-framework-simplejwt"],"created_at":"2025-02-12T22:50:43.116Z","updated_at":"2026-05-02T19:31:34.403Z","avatar_url":"https://github.com/mrshakil015.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Django JWT API Token and Email OTP Authentication\n\n## Context\n- [Project Setup](#project-setup)\n- [Configure JWT Token](#configure-jwt-token)\n- [Create Serializer Class](#create-serializer-class)\n    - [User Serializer](#userserializer)\n    - [User Register Serializer](#userregisterserializer)\n    - [User Login Serializer](#userloginserializer)\n    - [User Login OTP Serializer](#userloginotpserializer)\n- [Create View Methodology](#create-view-methodology)\n- [Email Configuration Documentations](#email-configuration)\n\n### Project Setup\n1. At first Create Environment:\n    ```cmd\n    python-m venv env\n    ```\n2. After Create envirionment activate the environment:\n    ```cmd\n    .\\env\\Scripts\\activate\n    ```\n3. Install Dependencies:\n    ```cmd\n    pip install -r requirements.txt\n    ```\n4. Create a Djnago Project:\n    ```cmd\n    django-admin startproject djangojwt\n    ```\n5. Change current directory to `djangojwt` folder:\n    ```cmd\n    cd djangojwt\n    ```\n6. Create a Django App:\n    ```cmd\n    django-admin startapp myapp\n    ```\n7. Update `settings.py` to Add `rest_framework` and `app_name` to `INSTALLED_APPS`:\n    ```python\n    INSTALLED_APPS = [\n    ......\n    ......\n    'rest_framework',\n    'myapp',\n    ]\n    ```\n⬆️ [Go to Context](#context)\n\n## Configure JWT Token\n- Install Required Libraries\n    ```cmd\n    pip install djangorestframework-simplejwt\n    ```\n- Update `settings.py` to Add `rest_framework_simplejwt` inside the `INSTALLED_APPS`:\n  ```python\n    INSTALLED_APPS = [\n    ......\n    ......\n    'rest_framework',\n    'rest_framework_simplejwt',\n    ]\n    ```\n\n- Then, your django project must be configured to use the library. In `settings.py`, add `rest_framework_simplejwt.authentication.JWTAuthentication` to the list of authentication classes:\n    ```python\n    REST_FRAMEWORK = {\n        'DEFAULT_AUTHENTICATION_CLASSES': (\n            'rest_framework_simplejwt.authentication.JWTAuthentication',\n        )\n    }\n    ```\n\n⬆️ [Go to Context](#context)\n### Final Setup\n- After Implement the Model Migrate the database:\n    ```cmd\n    py manage.py makemigrations\n    py manage.py migrate\n    ```\n- Create superuser\n    ```cmd\n    py manage.py createsuperuser\n    ```\n- Run the project\n    ```cmd\n    py manage.py runserver\n    ```\n⬆️ [Go to Context](#context)\n\n## Create Serializer Class:\n### UserSerializer\nTo configure the serializer create `serializers.py` file inside the `app`:\n- First create `UserSerializer` to get or store the user data:\n    ```python\n    from rest_framework import serializers\n    from django.contrib.auth.models import User\n\n    class UserSerializer(serializers.ModelSerializer):\n        class Meta:\n            model = User\n            fields = ['id','username','email','date_joined']\n    ```\n⬆️ [Go to Context](#context)\n\n### UserRegisterSerializer:\n- Create `UserRegisterSerializer` class for register the user information:\n    ```python\n    class UserRegisterSerializer(serializers.ModelSerializer):\n        id = serializers.PrimaryKeyRelatedField(read_only=True)\n        username = serializers.CharField()\n        first_name = serializers.CharField()\n        last_name = serializers.CharField()\n        email = serializers.EmailField()\n        password = serializers.CharField(write_only=True)\n        confirm_password = serializers.CharField(write_only=True)\n        \n        class Meta:\n            model = User\n            fields = ['id','username','first_name','last_name','email','password','confirm_password']\n            \n    ```\n- To validate the username create a function inside the `UserRegisterSerializer` class. This function check this user already exists or not.\n    ```python\n    from rest_framework.exceptions import ValidationError\n    def validate_username(self, username):\n        if User.objects.filter(username=username).exists():\n            detail = {\n                \"detail\": \"User Already exist!\"\n            }\n            raise ValidationError(detail=detail)\n        return username\n    ```\n- To validate the password matching and also check email already exists or not.\n    ```python\n    def validate(self, instance):\n        if instance['password'] != instance['confirm_password']:\n            raise ValidationError({\"message\":\"Both password must match\"})\n        if User.objects.filter(email=instance['email']).exists():\n            raise ValidationError({\"message\":\"Email already taken!\"})\n        return instance\n    ```\n- After validate the user then implement a functio name create to create the user.\n    ```python\n    def create(self, validated_data):\n        password = validated_data.pop('password')\n        confirm_password = validated_data.pop('confirm_password')\n        user = User.objects.create(**validated_data)\n        user.set_password(password)\n        user.save()\n        return user\n    ```\n⬆️ [Go to Context](#context)\n\n### UserLoginSerializer:\n- Create user login serializer\n    ```python\n    class UserLoginSerializer(serializers.ModelSerializer):\n        username = serializers.CharField()\n        password = serializers.CharField(write_only=True)\n        \n        class Meta:\n            model = User\n            fields = ['username', 'password']\n    ```\n⬆️ [Go to Context](#context)\n### UserLoginOTPSerializer:\n- Create user login otp serializer\n    ```python\n    class UserLoginOTPSerializer(serializers.Serializer):\n        username = serializers.CharField()\n        otp = serializers.CharField(max_length=6)\n    ```\n⬆️ [Go to Context](#context)\n\n## Create View Methodology\nCreate viewsets using diffent api view like: `ModelViewSet`, `GenericAPIView`, `APIView` method. Also import required libries:\n### User Register View\n- Here I create user registration method using `ModelViewSet` with the custom `@action` method for custom registration endpoint.\n    ```python\n    #Import the libries\n    from django.contrib.auth.models import User\n    from rest_framework import status,viewsets\n    from rest_framework.exceptions import MethodNotAllowed\n    from .serializers import UserRegisterSerializer\n    ```\n    ```python\n    class UserRegisterViewSet(viewsets.ModelViewSet):\n        queryset = User.objects.all()\n        serializer_class = UserRegisterSerializer\n    ```\n- `ModelViewSet` provide default create method. But here i need to customize the registration  that's why apply `MethodNotAllowed`. For that include the create function under the `UserRegisterViewSet` class:\n    ```python\n    def create(self, request, *args, **kwargs):\n        raise MethodNotAllowed(method=\"POST\",detail=\"User creation is not allowed on this endpoint. Go to '/users/register/' endpoint\")\n\n    ```\n- Now apply the custom registratio function under the `UserRegisterViewSet` class:\n    ```python\n    @action(methods=['post'], detail=False, url_path='register')\n    def register(self, request, *args, **kwargs):\n        serializer = self.get_serializer(data=request.data)\n        if serializer.is_valid():\n            user = serializer.save()\n            response = {\n                'success': True,\n                'user': {\n                    'id': user.id,\n                    'username': user.username,\n                    'email': user.email,\n                    'first_name': user.first_name,\n                    'last_name': user.last_name,\n                }\n            }\n            return Response(response, status=status.HTTP_201_CREATED)\n        raise ValidationError(serializer.errors, code=status.HTTP_400_BAD_REQUEST)\n    ```\n⬆️ [Go to Context](#context)\n\n### User Login View:\n- Here include the user login view. With the login functionalities include the user `JWT` Authentication and Email based `2FA OTP` authentication. Step by step process how a user can access their data into their dashboard or account:\n    - Goto `/api/login/` endpoint and Login using `username` and `password`\n    - After that send a `OTP` user registered email address.\n    - To validate the OTP goto `/api/verify-otp/` endpoint and verify the otp using username and otp.\n    - After validation generate a `refresh token` and `access token`. Using the `access token` user can access their data.\n- Before create login method configure the email configuration. Show the configuration here: [Click Here](#email-configuration)\n- Now create `Loginview` method. At first need to import some libries:\n    ```python\n    from rest_framework.exceptions import ValidationError\n    ```\n    Create an in-memory dictionary `otp_storage` to stored the OTP temporarily in an in-memory dictionary. It declare globally:\n    ```python\n    otp_storage = {}\n    ```\n    ```python\n    class LoginView(generics.GenericAPIView):\n    serializer_class = UserLoginSerializer\n\n    def post(self, request, *args, **kwargs):\n        username = request.data.get(\"username\")\n        password = request.data.get(\"password\")\n\n        if not username or not password:\n            raise ValidationError({\"message\": \"Username and password are required.\"})\n\n        # Authenticate the user\n        user = authenticate(username=username, password=password)\n        if user is None:\n            raise ValidationError({\"message\": \"Invalid credentials\"})\n\n        # Generate opt\n        otp = get_random_string(length=6, allowed_chars='1234567890')\n        otp_storage[username] = otp\n\n        # Send OTP to user's email\n        send_mail(\n            subject=\"Your OTP for Login\",\n            message=f\"Your OTP is {otp}. It is valid for 5 minutes.\",\n            from_email=\"shakil.eub.cse@gmail.com\",\n            recipient_list=[user.email],\n        )\n\n        return Response({\n            \"message\": \"OTP sent to your registered email address.\"\n            },\n            status=status.HTTP_200_OK\n        )\n\n    ```\n### OTP Verify View:\n- This function used of verify the otp.\n    ```python\n    class VerifyOtpView(generics.GenericAPIView):\n    serializer_class = UserLoginOTPSerializer\n    \n    def post(self, request, *args, **kwargs):\n        serializer = self.get_serializer(data=request.data)\n        serializer.is_valid(raise_exception=True)\n        \n        # Extract validated data\n        username = serializer.validated_data.get('username')\n        otp = serializer.validated_data.get('otp')\n\n        # Check if OTP exists for the username and validate it\n        if username not in otp_storage:\n            raise ValidationError({\"message\": \"OTP has not been sent or expired or username not valid.\"})\n        \n        # Validate OTP\n        if otp_storage[username] != otp:\n            raise ValidationError({\"message\": \"Invalid OTP.\"})\n\n        # Clean up OTP after verification\n        del otp_storage[username]\n\n        try:\n            user = User.objects.get(username=username)\n        except User.DoesNotExist:\n            raise ValidationError({\"message\": \"User does not exist.\"})\n\n        refresh = RefreshToken.for_user(user)\n        access_token = str(refresh.access_token)\n        user_serializer = UserSerializer(user)\n\n\n        return Response(\n            {\n                'access': access_token,\n                'refresh': str(refresh),\n                'user': user_serializer.data,\n            },\n            status=status.HTTP_200_OK\n        )\n    ```\n⬆️ [Go to Context](#context)\n\n## Email Configuration:\n-  Install `python-decouple`.It is a popular package for managing environment variables in Django.\n    ```cmd\n    pip install python-decouple\n    ```\n- Create a `.env` file in the root directory of your project (where manage.py is located). This file will store your sensitive data.\n    ```python\n    EMAIL_HOST=smtp.gmail.com\n    EMAIL_PORT=587\n    EMAIL_USE_TLS=True\n    EMAIL_USE_SSL=False\n    EMAIL_HOST_USER=your-email@gmail.com\n    EMAIL_HOST_PASSWORD=your-email-app-password\n    ```\n- Now how to get the email `EMAIL_HOST_PASSWORD`:\n    - Go to the Manage Google Account\n    - If 2FA not enable at first enable the 2FA\n    - Then Search `App Passwords`. And go to this page.\n    - Set any app name like: (e.g. Django App etc.)\n    - After that click create. Then it provide a 16-characters password. like this: `takv dcgx ldzo poll`. \n    - Then copy it and and using on the project.\n- Configure Email setting inside the `settings.py`:\n    ```python\n    from decouple import config\n\n    EMAIL_HOST = config('EMAIL_HOST', default='smtp.gmail.com')\n    EMAIL_PORT = config('EMAIL_PORT', default=587, cast=int)\n    EMAIL_USE_TLS = config('EMAIL_USE_TLS', default=True, cast=bool)\n    EMAIL_USE_SSL = config('EMAIL_USE_SSL', default=False, cast=bool)\n    EMAIL_HOST_USER = config('EMAIL_HOST_USER', default='')\n    EMAIL_HOST_PASSWORD = config('EMAIL_HOST_PASSWORD', default='')\n    ```\n    If fetch any error using `from decouple import config` this package. Then used bellow method:\n    ```python\n    from dotenv import load_dotenv\n    import os\n\n    # Email configuration from environment variables\n    EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'\n\n    EMAIL_HOST = os.getenv('EMAIL_HOST', 'smtp.gmail.com')\n    EMAIL_PORT = int(os.getenv('EMAIL_PORT', 587))\n    EMAIL_USE_TLS = os.getenv('EMAIL_USE_TLS', 'True') == 'True'\n    EMAIL_USE_SSL = os.getenv('EMAIL_USE_SSL', 'False') == 'True'\n    EMAIL_HOST_USER = os.getenv('EMAIL_HOST_USER', '')\n    EMAIL_HOST_PASSWORD = os.getenv('EMAIL_HOST_PASSWORD', '')\n    ```\n- Sending Email views:\n    ```python\n    from django.core.mail import send_mail\n    from django.conf import settings\n\n    def send_otp_email(user, otp):\n        send_mail(\n            subject=\"Your OTP for Login\",\n            message=f\"Your OTP is {otp}. It is valid for 5 minutes.\",\n            from_email=settings.EMAIL_HOST_USER,\n            recipient_list=[user.email],\n        )\n    ```\n⬆️ [Go to Context](#context)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmrshakil015%2Fdjango-jwt-api-token-authentication","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmrshakil015%2Fdjango-jwt-api-token-authentication","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmrshakil015%2Fdjango-jwt-api-token-authentication/lists"}