DEV Community

Cover image for JWT in Django Rest Framework: Building Secure Auth from Scratch
Zabby
Zabby

Posted on

JWT in Django Rest Framework: Building Secure Auth from Scratch

Why I moved beyond Django’s default auth system and how JWT unlocked modular, secure, and scalable authentication.

Why Not Django’s Default Login?

Let’s face it session-based auth is fine for traditional sites, but once I started building SPAs with React, things got clunky. I needed:

  • Stateless auth for mobile + frontend clients
  • Token refresh flow
  • Endpoint flexibility

Enter JSON Web Tokens (JWT) my passport to modern Django authentication.


Setup with Django Rest Framework + djangorestframework-simplejwt

Installation

pip install djangorestframework djangorestframework-simplejwt 
Enter fullscreen mode Exit fullscreen mode

Add to settings.py

INSTALLED_APPS = [ 'rest_framework', ] REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES': ( 'rest_framework_simplejwt.authentication.JWTAuthentication', ), } 
Enter fullscreen mode Exit fullscreen mode

Core JWT Views

DRF SimpleJWT gives you these out of the box:

from rest_framework_simplejwt.views import ( TokenObtainPairView, TokenRefreshView, ) urlpatterns = [ path("api/token/", TokenObtainPairView.as_view(), name="token_obtain_pair"), path("api/token/refresh/", TokenRefreshView.as_view(), name="token_refresh"), ] 
Enter fullscreen mode Exit fullscreen mode

But I prefer customizing TokenObtainPairSerializer to include user data in the token response.


Custom Serializer Example

Let’s enrich token responses:

from rest_framework_simplejwt.serializers import TokenObtainPairSerializer class CustomTokenObtainPairSerializer(TokenObtainPairSerializer): @classmethod def get_token(cls, user): token = super().get_token(user) token['username'] = user.username token['role'] = user.role # assuming custom field return token def validate(self, attrs): data = super().validate(attrs) data['user'] = { 'username': self.user.username, 'email': self.user.email } return data 
Enter fullscreen mode Exit fullscreen mode

Then wire into views:

from rest_framework_simplejwt.views import TokenObtainPairView class CustomTokenObtainPairView(TokenObtainPairView): serializer_class = CustomTokenObtainPairSerializer 
Enter fullscreen mode Exit fullscreen mode

Auth-Protected Views

Using IsAuthenticated in any DRF view:

from rest_framework.permissions import IsAuthenticated class ProfileView(APIView): permission_classes = [IsAuthenticated] def get(self, request): return Response({"user": request.user.username}) 
Enter fullscreen mode Exit fullscreen mode

The frontend just sends the token in the Authorization header:

Authorization: Bearer <your_jwt_token>


Teaching JWT Auth: My Favorite Metaphors

When explaining JWT to students, I use:

  • Passport Analogy: Token carries your identity; the server doesn’t need to remember you.

  • Sticker System: Each JWT is like a sticker pack with claims; don’t trade stickers with strangers.

  • Renewable Visa: Refresh tokens = long-term travel permits.

The goal is to demystify headers, expiry, and token rotation.


Final Thoughts

JWT turned my Django APIs into elegant, frontend-friendly systems. Stateless auth brings clarity, speed, and trust and when structured right, it’s modular, secure, and a joy to maintain.

Top comments (0)