---
title: "Add JWT Authentication to Your Django REST Framework API"
description: ""
canonicalUrl: "https://zuplo.com/use-cases/api-key-auth/python/djangorestframework/jwt-backend"
framework: "Django REST Framework"
language: "Python"
authStrategy: "JWT with JWKS"
pageType: use-case
---

# Add JWT Authentication to Your Django REST Framework API



## How Zuplo Handles It

Let Zuplo issue short-lived JWTs signed with a JWKS your Django REST Framework backend can verify — no long-lived API keys touch your origin.

## Django REST Framework Backend Code

```python
import requests
from jose import jwt, JWTError
from django.conf import settings
from rest_framework import authentication, exceptions

# Replace with your actual Zuplo deployment name or custom domain
ISSUER = "https://my-api-a32f34.zuplo.api/__zuplo/issuer"
JWKS_URL = f"{ISSUER}/.well-known/jwks.json"

# Cache the JWKS
jwks_cache = {}

def get_jwks():
    if 'keys' not in jwks_cache:
        response = requests.get(JWKS_URL)
        response.raise_for_status()
        jwks_cache['keys'] = response.json().get('keys', [])
    return jwks_cache['keys']

def get_signing_key(kid):
    keys = get_jwks()
    for key in keys:
        if key['kid'] == kid:
            return key
    raise exceptions.AuthenticationFailed('Unable to find a signing key that matches.')

class JWTAuthentication(authentication.BaseAuthentication):

    def authenticate(self, request):
        auth_header = request.headers.get('Authorization')
        if not auth_header:
            return None

        try:
            token = auth_header.split(' ')[1]
            unverified_header = jwt.get_unverified_header(token)
            rsa_key = get_signing_key(unverified_header['kid'])
            payload = jwt.decode(
                token,
                rsa_key,
                algorithms='RS256',
                audience='your-audience-here',  # Adjust as needed
                issuer=ISSUER
            )
        except JWTError as e:
            raise exceptions.AuthenticationFailed(f'JWT validation failed: {str(e)}')

        return (payload, token)

# Example of a protected view
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.permissions import IsAuthenticated

class ProtectedView(APIView):
    authentication_classes = [JWTAuthentication]
    permission_classes = [IsAuthenticated]

    def get(self, request):
        return Response({
            "message": "Access granted",
            "user": request.user
        })
```

## Example Request

```bash
curl -X GET \
  'https://your-api.zuplo.dev/your-route' \
  -H 'Authorization: Bearer YOUR_API_KEY'
```

## Learn More

- [API Key Authentication on Zuplo](https://zuplo.com/docs/policies/api-key-auth-inbound)
- [JWT Authentication on Zuplo](https://zuplo.com/docs/policies/open-id-jwt-auth-inbound)
- [All use cases](https://zuplo.com/use-cases)
