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.

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.


๐Ÿ’ก Core Examples: Why You Should Use It

1. The Direct Approach (FastAPI Dependency)

Validate a token in FastAPI without letting the JWT library block your event loop with hidden network calls.

from fastapi import FastAPI, Depends, HTTPException, Request
from async_jwt_core import Validator, ValidationError

app = FastAPI()
validator = Validator(algorithms=["RS256"])

@app.get("/protected")
async def protected_route(request: Request):
    try:
        # Extract token from request headers
        token = Validator.extract_token(request)
        
        # YOU fetch the keys (e.g., from Redis). No hidden I/O!
        jwks = await my_custom_key_fetcher() 
        
        # Validate!
        claims = await validator.validate(token, jwks)
        return {"message": f"Welcome {claims.sub}!"}
        
    except ValidationError as e:
        raise HTTPException(status_code=401, detail=str(e))

2. The Middleware Approach (FastAPI)

Just like you add CORSMiddleware, you can add our FastAPIMiddleware to protect all routes automatically!

from fastapi import FastAPI
from async_jwt_core import Validator
from async_jwt_core.middleware import FastAPIMiddleware

app = FastAPI()

# 1. Initialize validator (Uses ASYNC_JWT_ISSUER from ENV)
validator = Validator(algorithms=["RS256"])

# 2. Add middleware just like CORSMiddleware!
app.add_middleware(
    FastAPIMiddleware,
    validator=validator,
    jwks={"keys": [...]} # Pass your JWKS here
)

@app.get("/protected")
async def protected_route(request: Request):
    # Claims are automatically attached to request.state!
    claims = request.state.user_claims
    return {"message": f"Hello {claims.sub}"}

๐Ÿ† Feature Showcase: Why We Are the Best

Here is a comparison of why async-jwt-core is the ultimate choice for modern Python web applications:

Feature / Capability Standard PyJWT Framework Libs async-jwt-core
Async Native โŒ (Sync only) ๐ŸŸก (Sometimes) โœ…
Zero I/O (Absolute Control) โœ… โŒ (Often fetches keys) โœ…
No Framework Lock-in โœ… โŒ (FastAPI/Django only) โœ…
Extensible Algorithms โŒ (Hard to add) โŒ (Hard to add) โœ…
In-built Middlewares โŒ โŒ โœ… (FastAPI, Flask, Django)
In-built Rate Limiting โŒ โŒ โœ… (Token Bucket)
JWE Decryption โŒ โŒ โœ… (RSA-OAEP + AES-GCM)
Token Creation (Signing) โœ… โŒ โœ…
Role & Scope Validation (RBAC) โŒ (Do it yourself) โŒ (Do it yourself) โœ…
Access IDs Validation โŒ (Do it yourself) โŒ (Do it yourself) โœ…
Session ID Validation โŒ (Do it yourself) โŒ (Do it yourself) โœ…

๐Ÿ”ฌ How to Test Your Application

Testing an application that uses async-jwt-core is easy. You can mock the Validator or create valid tokens for testing using Encoder.

Here is an example using pytest and httpx to test a FastAPI endpoint:

import pytest
from httpx import AsyncClient
from async_jwt_core import Encoder

@pytest.mark.asyncio
async def test_protected_route():
    from my_app import app # Import your FastAPI app
    
    # 1. Create a valid token for testing
    header = {"alg": "HS256", "kid": "test-key"}
    payload = {"sub": "user123", "roles": ["admin"]}
    secret = "my-test-secret"
    
    token = Encoder.create_token(header, payload, secret)
    
    # 2. Call your protected endpoint
    async with AsyncClient(app=app, base_url="http://test") as ac:
        response = await ac.get(
            "/protected",
            headers={"Authorization": f"Bearer {token}"}
        )
        
    assert response.status_code == 200
    assert response.json()["message"] == "Welcome user123!"

โœจ Key Features

  • ๐Ÿ”’ Zero Network I/O โ€“ Keys are fetched externally.
  • โšก Async-Only API โ€“ Designed from the ground up for asyncio.
  • ๐Ÿงฉ Framework Agnostic โ€“ Works with FastAPI, Sanic, aiohttp, Flask, or Django.
  • ๐ŸŽฏ Custom Claim Validation โ€“ Pass your own validation functions.
  • ๐Ÿ“ฆ Ultra Lightweight โ€“ Only depends on cryptography.

๐Ÿ” Supported Algorithms

We support a vast range of modern cryptographic algorithms out of the box (13 total): HS256, HS384, HS512, RS256, RS384, RS512, PS256, PS384, PS512, ES256, ES384, ES512, EdDSA.

๐Ÿ“– Examples (References for Users)

We provide full working examples in the GitHub repository:

  • ๐Ÿ“„ Basic Usage: Shows how to create and validate a token.
  • ๐Ÿš€ FastAPI Demo: Shows how to integrate with FastAPI.
  • ๐ŸŒถ๏ธ Flask Demo: Shows how to use it in Flask.
  • ๐ŸŽธ Django Demo: Shows how to use it in Django.

๐Ÿ› ๏ธ Installation

uv add async-jwt-core

๐Ÿ“„ 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.6.tar.gz (16.5 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.6-py3-none-any.whl (19.5 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: async_jwt_core-0.2.6.tar.gz
  • Upload date:
  • Size: 16.5 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.6.tar.gz
Algorithm Hash digest
SHA256 f38be4ca85194aa75bb0ff3b545d6ce4074c346a5de636422985e3e218e8692a
MD5 e93e8786a59598c69d286972265bf5d3
BLAKE2b-256 01bb619d1200ef4caaf439cf38e485ef2b24f3818415c0b3e9eeaf7f9cda8643

See more details on using hashes here.

File details

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

File metadata

  • Download URL: async_jwt_core-0.2.6-py3-none-any.whl
  • Upload date:
  • Size: 19.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.6-py3-none-any.whl
Algorithm Hash digest
SHA256 8b2369827c87796331e9ce8a17bbb51e88459696970cf6542fc66347d7c2404a
MD5 1e8005585f33a8d6cefaa9d1e6c754e4
BLAKE2b-256 9720e04d53ea0972cf78b3c51ed0af6d4b3cf8b728f47e690e8fca7d7f66f0de

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