Skip to main content
Pre-release

This release is a pre-release and may not be stable for production use.

axioms-fastapi

OAuth2/OIDC authentication and authorization for FastAPI APIs. Supports authentication and claim-based fine-grained authorization (scopes, roles, permissions) using JWT tokens.

Works with access tokens issued by various authorization servers including AWS Cognito, Auth0, Okta, Microsoft Entra, etc.

Features

  • JWT token validation with automatic public key retrieval from JWKS endpoints
  • Algorithm validation to prevent algorithm confusion attacks (only secure asymmetric algorithms allowed)
  • Issuer validation (iss claim) to prevent token substitution attacks
  • FastAPI dependency injection for authentication and authorization
  • Flexible configuration with support for custom JWKS and issuer URLs
  • Support for custom claim and/or namespaced claims names to support different authorization servers
  • Async-ready and production-tested

Installation

pip install axioms-fastapi

Quick Start

1. Configure your FastAPI application

from fastapi import FastAPI, Depends
from axioms_fastapi import init_axioms, require_auth, require_scopes

app = FastAPI()

# Initialize Axioms with your configuration
init_axioms(
    app,
    AXIOMS_AUDIENCE="your-api-audience",
    AXIOMS_DOMAIN="your-auth.domain.com"
)

2. Protect your routes

from axioms_fastapi import require_auth, require_permissions

@app.get("/api/protected")
async def protected_route(payload=Depends(require_auth)):
    """Route protected by JWT authentication."""
    user_id = payload.sub
    return {"user_id": user_id, "message": "Authenticated"}

@app.get("/api/admin")
async def admin_route(
    payload=Depends(require_auth),
    _=Depends(require_permissions(["admin:write"]))
):
    """Route requiring admin:write permission."""
    return {"message": "Admin access granted"}

Configuration

The SDK supports the following configuration options:

  • AXIOMS_AUDIENCE (required): Your resource identifier or API audience
  • AXIOMS_DOMAIN (optional): Your auth domain - constructs issuer and JWKS URLs
  • AXIOMS_ISS_URL (optional): Full issuer URL for validating the iss claim (recommended for security)
  • AXIOMS_JWKS_URL (optional): Full URL to your JWKS endpoint

Configuration Hierarchy:

  1. AXIOMS_DOMAIN → constructs → AXIOMS_ISS_URL (if not explicitly set)
  2. AXIOMS_ISS_URL → constructs → AXIOMS_JWKS_URL (if not explicitly set)

Environment Variables

Create a .env file:

AXIOMS_AUDIENCE=your-api-audience
AXIOMS_DOMAIN=your-auth.domain.com

# OR for custom configurations:
# AXIOMS_ISS_URL=https://your-auth.domain.com/oauth2
# AXIOMS_JWKS_URL=https://your-auth.domain.com/.well-known/jwks.json

Usage Examples

Basic Authentication

from fastapi import FastAPI, Depends
from axioms_fastapi import init_axioms, require_auth

app = FastAPI()
init_axioms(app, AXIOMS_AUDIENCE="api.example.com", AXIOMS_DOMAIN="auth.example.com")

@app.get("/profile")
async def get_profile(payload=Depends(require_auth)):
    return {
        "user_id": payload.sub,
        "email": payload.get("email"),
        "name": payload.get("name")
    }

Scope-Based Authorization (OR Logic)

from axioms_fastapi import require_auth, require_scopes

@app.get("/api/resource")
async def resource_route(
    payload=Depends(require_auth),
    _=Depends(require_scopes(["read:resource", "write:resource"]))
):
    # User needs EITHER 'read:resource' OR 'write:resource' scope
    return {"data": "success"}

Role-Based Authorization

from axioms_fastapi import require_auth, require_roles

@app.get("/admin/users")
async def admin_route(
    payload=Depends(require_auth),
    _=Depends(require_roles(["admin", "superuser"]))
):
    # User needs EITHER 'admin' OR 'superuser' role
    return {"users": []}

Permission-Based Authorization

from axioms_fastapi import require_auth, require_permissions

@app.post("/api/resource")
async def create_resource(
    payload=Depends(require_auth),
    _=Depends(require_permissions(["resource:create"]))
):
    return {"message": "Resource created"}

AND Logic (Chaining Dependencies)

@app.get("/api/strict")
async def strict_route(
    payload=Depends(require_auth),
    _=Depends(require_scopes(["read:resource"])),
    __=Depends(require_scopes(["write:resource"]))
):
    # User needs BOTH 'read:resource' AND 'write:resource' scopes
    return {"data": "requires both scopes"}

Mixed Authorization

@app.get("/api/advanced")
async def advanced_route(
    payload=Depends(require_auth),
    _=Depends(require_scopes(["openid", "profile"])),  # openid OR profile
    __=Depends(require_roles(["editor"])),              # AND editor role
    ___=Depends(require_permissions(["resource:read", "resource:write"]))  # AND read OR write
):
    # User needs: (openid OR profile) AND (editor) AND (read OR write)
    return {"data": "complex authorization"}

Custom Claim Names

Support for different authorization servers with custom claim names:

init_axioms(
    app,
    AXIOMS_AUDIENCE="api.example.com",
    AXIOMS_DOMAIN="auth.example.com",
    AXIOMS_ROLES_CLAIMS=["cognito:groups", "roles"],
    AXIOMS_PERMISSIONS_CLAIMS=["permissions", "cognito:roles"],
    AXIOMS_SCOPE_CLAIMS=["scope", "scp"]
)

Error Handling

The SDK raises AxiomsHTTPException for authentication and authorization errors:

from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse
from axioms_fastapi import init_axioms, AxiomsHTTPException

app = FastAPI()
init_axioms(app, AXIOMS_AUDIENCE="api.example.com", AXIOMS_DOMAIN="auth.example.com")

@app.exception_handler(AxiomsHTTPException)
async def axioms_exception_handler(request: Request, exc: AxiomsHTTPException):
    return JSONResponse(
        status_code=exc.status_code,
        content=exc.detail,
        headers=exc.headers
    )

Security Features

  • Algorithm Validation: Only secure asymmetric algorithms allowed (RS256, RS384, RS512, ES256, ES384, ES512, PS256, PS384, PS512)
  • Issuer Validation: Validates iss claim to prevent token substitution attacks
  • Automatic JWKS Retrieval: Fetches and caches public keys from JWKS endpoints
  • Token Expiration: Validates exp claim
  • Audience Validation: Validates aud claim
  • Key ID Validation: Validates kid header

License

MIT

Release files for axioms-fastapi 0.0.1rc11762694952

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for axioms-fastapi 0.0.1rc11762694952
File Size Uploaded
axioms_fastapi-0.0.1rc11762694952.tar.gz 34.1 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for axioms-fastapi 0.0.1rc11762694952
File Interpreter ABI Platform
axioms_fastapi-0.0.1rc11762694952-py3-none-any.whl Python 3 none any Details

Total release size: 48.2 kB

Release files / axioms_fastapi-0.0.1rc11762694952.tar.gz

Download URL axioms_fastapi-0.0.1rc11762694952.tar.gz
Size 34.1 kB
Tags Source
SHA-256 checksum
How to use checksums
d5df15511d0ec8b3d8cecddb1126faccc3fb89df8e34f22c5029d4be7e1b8890
BLAKE2b-256 checksum
How to use checksums
b8bd4e88507c49b4c3ca358e06ee06cf8cbf80e87c421f0ff44627dba981bc5d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 9, 2025.

Transparency log

Release files / axioms_fastapi-0.0.1rc11762694952-py3-none-any.whl

Download URL axioms_fastapi-0.0.1rc11762694952-py3-none-any.whl
Size 14.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
802b09ab39b60f53323ff14fa65365a1924c36cca95e331bdfa89592d9f38ca9
BLAKE2b-256 checksum
How to use checksums
87bbba77f6be6302009b68a174006c9137ab084bcabef3812327a76f8426a3ac
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 9, 2025.

Transparency log
Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page