Skip to main content

A minimal, spec-first, framework-agnostic, async-only JWT validator with zero network dependencies.

Project description

async-jwt-core

A minimal, spec-first, framework-agnostic, async-only JWT validator with zero network dependencies.

PyPI version License: MIT


🚀 Why async-jwt-core? (The Problem We Solve)

In the modern Python async ecosystem, validating JWTs using JSON Web Key Sets (JWKS) usually forces you into one of two bad situations:

  1. Framework Lock-in: Libraries tied directly to FastAPI, Starlette, or Django.
  2. Opinionated I/O: Libraries that insist on making network calls for you (often using specific HTTP clients) to fetch keys, making it hard to implement custom caching (like Redis) or use your own HTTP session.

async-jwt-core solves this by doing exactly one thing perfectly: Pure Cryptographic Validation without I/O.

We provide the core validation logic. You bring the keys. This gives you absolute control over how keys are fetched, cached, and stored, while ensuring your event loop never blocks.

✨ Key Features

  • 🔒 Zero Network I/O – Keys are fetched externally. The validator only does the heavy lifting (crypto and claim checks).
  • Async-Only API – Designed from the ground up for asyncio.
  • 🧩 Framework Agnostic – Works with FastAPI, Sanic, aiohttp, or even pure Python background workers.
  • 🛠️ Highly Modular & Extensible – Want to add a custom algorithm? Just inherit from Algorithm and register it.
  • 🎯 Custom Claim Validation – Pass your own validation functions to enforce business rules during the validation phase.
  • 📦 Ultra Lightweight – Only depends on cryptography for secure signature verification.

🔐 Supported Algorithms

We support a vast range of modern cryptographic algorithms out of the box:

Type Algorithms
HMAC (Symmetric) HS256, HS384, HS512
RSA (Asymmetric) RS256, RS384, RS512
RSA-PSS (Asymmetric) PS256, PS384, PS512
ECDSA (Elliptic Curve) ES256, ES384, ES512

🌟 Extra Features to Help You

To make your life easier, we include features that other libraries charge you in complexity:

1. JSON Web Encryption (JWE) Support

We don't just do signing. We now support JWE decryption (RSA-OAEP with AES-GCM). This allows you to handle encrypted tokens where the payload is hidden.

from async_jwt_core import JWE

# Decrypt an encrypted token
decrypted_payload = await JWE.decrypt(token, private_key)

2. Unverified Decoding

Need to check the claims or header before you validate the token? No problem.

header = await validator.get_unverified_header(token)
payload = await validator.decode_unverified(token)

3. Built-in Async JWKS Cache

Even though we don't do I/O, we provide a simple async in-memory cache with TTL so you don't have to write your own.

from async_jwt_core import JWKSCache

cache = JWKSCache(ttl=3600)

# In your request handler:
jwks = await cache.get()
if not jwks:
    jwks = await fetch_jwks_from_web()
    await cache.set(jwks)

🛠️ Installation

uv add async-jwt-core
# or
pip install async-jwt-core

📖 Usage Examples

The Standard Use Case (With External Fetching)

import asyncio
import aiohttp
from async_jwt_core import Validator, ValidationError

# Initialize once
validator = Validator(
    algorithms=["RS256", "ES256"],
    issuer="https://YOUR-AUTH-DOMAIN.com",
    audience="YOUR-API-AUDIENCE"
)

async def fetch_jwks(url: str) -> dict:
    async with aiohttp.ClientSession() as session:
        async with session.get(url) as resp:
            return await resp.json()

async def authenticate(token: str):
    jwks = await fetch_jwks("https://YOUR-AUTH-DOMAIN.com/.well-known/jwks.json")
    
    try:
        claims = await validator.validate(token, jwks)
        print(f"Authenticated user: {claims.sub}")
        return claims
    except ValidationError as e:
        print(f"Auth failed: {e}")
        return None

⚖️ Why We Are Better

Feature Standard PyJWT Framework Libs async-jwt-core
Async Native ❌ (Sync only) (Sometimes)
Zero I/O ❌ (Often fetches keys)
No Lock-in ❌ (FastAPI/Django only)
Extensible Algs ❌ (Hard to add) ❌ (Hard to add)

🤝 Contributing

We built this for the community! If you want to add support for more algorithms (like EdDSA) or improve the claims system, check out our modular folder structure in src/async_jwt_core/algorithms/. It is designed to be easy to extend.

📄 License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

async_jwt_core-0.2.1.tar.gz (10.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

async_jwt_core-0.2.1-py3-none-any.whl (13.5 kB view details)

Uploaded Python 3

File details

Details for the file async_jwt_core-0.2.1.tar.gz.

File metadata

  • Download URL: async_jwt_core-0.2.1.tar.gz
  • Upload date:
  • Size: 10.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.13

File hashes

Hashes for async_jwt_core-0.2.1.tar.gz
Algorithm Hash digest
SHA256 42ae083063793316e8b4f1a4518b51874c6111f499590650843721a4c48cde51
MD5 f7a2fdeffb30ec03c6add42c4c0c9b51
BLAKE2b-256 6bbc53d63aef3b768412623c22e03add70848b25934649f34bd11645412569c0

See more details on using hashes here.

File details

Details for the file async_jwt_core-0.2.1-py3-none-any.whl.

File metadata

  • Download URL: async_jwt_core-0.2.1-py3-none-any.whl
  • Upload date:
  • Size: 13.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.13

File hashes

Hashes for async_jwt_core-0.2.1-py3-none-any.whl
Algorithm Hash digest
SHA256 d7e9b1bab89fd7c6fa1ae11043e57b05db70a89666527637c70792045f7a283d
MD5 b9d2d97d46f7223220db51617c2ba4f1
BLAKE2b-256 84d6f88690704507dcbb4a70800504f5029da2c6e78a650096696249805ce3f1

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page