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

# Add JWT Authentication to Your Falcon API

Secure your Falcon API using JWT authentication with JWKS.

## How Zuplo Handles It

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

## Falcon Backend Code

```python
import falcon
from jose import jwt
from jose.exceptions import JWTError, ExpiredSignatureError
import requests
from cachetools import TTLCache

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

# Cache for JWKS keys
jwks_cache = TTLCache(maxsize=10, ttl=600)

def get_jwks():
    if JWKS_URL not in jwks_cache:
        resp = requests.get(JWKS_URL)
        resp.raise_for_status()
        jwks_cache[JWKS_URL] = resp.json()
    return jwks_cache[JWKS_URL]

def get_key(token):
    unverified_header = jwt.get_unverified_header(token)
    jwks = get_jwks()
    for jwk in jwks['keys']:
        if jwk['kid'] == unverified_header['kid']:
            return jwt.algorithms.RSAAlgorithm.from_jwk(jwk)
    raise JWTError("Unable to find appropriate key")

class JWTAuthMiddleware:
    def process_request(self, req, resp):
        auth_header = req.get_header('Authorization')
        if not auth_header or not auth_header.startswith('Bearer '):
            raise falcon.HTTPUnauthorized(description='No token provided')

        token = auth_header[7:]
        try:
            key = get_key(token)
            payload = jwt.decode(token, key, algorithms=ALGORITHMS, issuer=ISSUER)
            req.context.user = payload
        except ExpiredSignatureError:
            raise falcon.HTTPUnauthorized(description='Token has expired')
        except JWTError as e:
            raise falcon.HTTPUnauthorized(description=f'Invalid token: {str(e)}')

class ProtectedResource:
    def on_get(self, req, resp):
        resp.media = {'message': 'Access granted', 'user': req.context.user}

app = falcon.App(middleware=[JWTAuthMiddleware()])
app.add_route('/protected', ProtectedResource())

if __name__ == '__main__':
    from wsgiref.simple_server import make_server
    with make_server('', 8000, app) as httpd:
        httpd.serve_forever()
```

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