Avnology ID
Guides

Verify JWTs (Python)

Validate Avnology ID access tokens locally using avnology_id.backend.jwt.

Verify JWTs in Python

The avnology_id.backend extra ships a JWTVerifier wrapping PyJWKClient with a 5-minute JWKS cache and Avnology-native claim types.

Install

pip install "avnology-id[backend]"

The [backend] extra pulls in pyjwt and cryptography.

Minimum viable verifier

FastAPI dependency

The shipped avnology_id.fastapi module wraps this with Depends(require_auth):

from fastapi import Depends, FastAPI
from avnology_id.fastapi import require_auth, current_user
from avnology_id.backend import AvnologyClaims

app = FastAPI()

@app.get("/api/me")

Configure the verifier once via configure_avnology_fastapi(issuer=..., audience=...) before first request.

Django middleware

# settings.py
MIDDLEWARE = [
    ...,
    "avnology_id.django.AvnologyAuthMiddleware",
]

AVNOLOGY_ID = {
    "issuer": "https://api-id.avnology.net",
    "audience": "my-api"

Then in views:

from avnology_id.django import require_auth

@require_auth
def me(request):
    return JsonResponse({"user_id": request.avnology_claims.user_id})

Flask decorator

from flask import Flask, g, jsonify
from avnology_id.flask import require_auth, configure_avnology_flask

app = Flask(__name__)
configure_avnology_flask(
    app,
    issuer="https://api-id.avnology.net",






Claim reference

@dataclass(frozen=True)
class AvnologyClaims:
    subject: str
    user_id: str
    organization_id: str | None = None
    session_id: str








Error handling

Every failure raises JWTVerifierError:

from avnology_id.backend import JWTVerifier, JWTVerifierError

try:
    claims = verifier.verify(token)
except JWTVerifierError as err:
    # err.args[0] carries a machine-readable reason:
    # "expired", "invalid_signature", "audience_mismatch", "issuer_mismatch",
    # "jwks_fetch_failed", "not_yet_valid"

Sync vs async

JWTVerifier.verify is sync. If you're inside an async handler and want to avoid blocking the loop, call it via anyio.to_thread:

import anyio

claims = await anyio.to_thread.run_sync(verifier.verify, token)

The shipped FastAPI dependency does this automatically.