---
title: "Add JWT Authentication to Your Sanic API"
description: "Secure your Sanic API using JWT authentication with JWKS."
canonicalUrl: "https://zuplo.com/use-cases/api-key-auth/python/sanic/jwt-backend"
framework: "Sanic"
language: "Python"
authStrategy: "JWT with JWKS"
pageType: use-case
---

# Add JWT Authentication to Your Sanic API

Secure your Sanic API using JWT authentication with JWKS.

## How Zuplo Handles It

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

## Sanic Backend Code

```python
from sanic import Sanic, response
from sanic.exceptions import Unauthorized
from sanic.request import Request
import jwt
import aiohttp
from jwt import PyJWKClient

app = Sanic("jwt_example")

ISSUER = "https://my-api-a32f34.zuplo.api/__zuplo/issuer"
JWKS_URL = f"{ISSUER}/.well-known/jwks.json"

async def get_signing_key(token):
    try:
        jwks_client = PyJWKClient(JWKS_URL)
        signing_key = jwks_client.get_signing_key_from_jwt(token).key
        return signing_key
    except Exception as e:
        raise Unauthorized("Invalid token") from e

async def validate_jwt(request: Request):
    auth_header = request.headers.get("Authorization", None)
    if not auth_header:
        raise Unauthorized("No token provided")

    token = auth_header.replace("Bearer ", "")

    try:
        signing_key = await get_signing_key(token)
        decoded = jwt.decode(
            token,
            signing_key,
            algorithms=["RS256"],
            issuer=ISSUER
        )
        request.ctx.user = decoded
    except Exception as e:
        raise Unauthorized("Invalid token") from e

@app.middleware("request")
async def jwt_middleware(request: Request):
    if request.path.startswith("/protected"):
        await validate_jwt(request)

@app.get("/protected")
async def protected(request: Request):
    user = request.ctx.user
    return response.json({
        "message": "Access granted",
        "user": user
    })

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=8000)
```

## 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)
