OAuth2/OIDC authentication and authorization for FastAPI APIs
Project description
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 (
issclaim) 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 audienceAXIOMS_DOMAIN(optional): Your auth domain - constructs issuer and JWKS URLsAXIOMS_ISS_URL(optional): Full issuer URL for validating theissclaim (recommended for security)AXIOMS_JWKS_URL(optional): Full URL to your JWKS endpoint
Configuration Hierarchy:
AXIOMS_DOMAIN→ constructs →AXIOMS_ISS_URL(if not explicitly set)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
issclaim to prevent token substitution attacks - Automatic JWKS Retrieval: Fetches and caches public keys from JWKS endpoints
- Token Expiration: Validates
expclaim - Audience Validation: Validates
audclaim - Key ID Validation: Validates
kidheader
License
MIT
Links
- Documentation: https://axioms-fastapi.abhishek-tiwari.com
- Source Code: https://github.com/abhishektiwari/axioms-fastapi
- Issue Tracker: https://github.com/abhishektiwari/axioms-fastapi/issues
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file axioms_fastapi-0.0.1rc11762698864.tar.gz.
File metadata
- Download URL: axioms_fastapi-0.0.1rc11762698864.tar.gz
- Upload date:
- Size: 34.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
807df3337f7e8d981ee62239fc3724dd73c138a55c13282d4147982e1ac6d59f
|
|
| MD5 |
86a8444999a2c595eb692cb3e93e0104
|
|
| BLAKE2b-256 |
b9fd715b5231bd2020b6b6892308b706e67376b575d0cd6f0771e18469d36457
|
Provenance
The following attestation bundles were made for axioms_fastapi-0.0.1rc11762698864.tar.gz:
Publisher:
release.yml on abhishektiwari/axioms-fastapi
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
axioms_fastapi-0.0.1rc11762698864.tar.gz -
Subject digest:
807df3337f7e8d981ee62239fc3724dd73c138a55c13282d4147982e1ac6d59f - Sigstore transparency entry: 685801201
- Sigstore integration time:
-
Permalink:
abhishektiwari/axioms-fastapi@35481f2e265d9dc27943a8daf39bd9ce43606fbb -
Branch / Tag:
refs/pull/1/merge - Owner: https://github.com/abhishektiwari
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@35481f2e265d9dc27943a8daf39bd9ce43606fbb -
Trigger Event:
pull_request
-
Statement type:
File details
Details for the file axioms_fastapi-0.0.1rc11762698864-py3-none-any.whl.
File metadata
- Download URL: axioms_fastapi-0.0.1rc11762698864-py3-none-any.whl
- Upload date:
- Size: 14.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
07c736df6acb5da2cc782eb7bfcc68ad9fa1a829a8fecfdef4da8c08bc698dd2
|
|
| MD5 |
4958ded4ddb6b261d5c168003a028e9e
|
|
| BLAKE2b-256 |
ae1a2946387311718c88b10a7f0e692103a74d6a116ebbe9717aff16cc694587
|
Provenance
The following attestation bundles were made for axioms_fastapi-0.0.1rc11762698864-py3-none-any.whl:
Publisher:
release.yml on abhishektiwari/axioms-fastapi
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
axioms_fastapi-0.0.1rc11762698864-py3-none-any.whl -
Subject digest:
07c736df6acb5da2cc782eb7bfcc68ad9fa1a829a8fecfdef4da8c08bc698dd2 - Sigstore transparency entry: 685801202
- Sigstore integration time:
-
Permalink:
abhishektiwari/axioms-fastapi@35481f2e265d9dc27943a8daf39bd9ce43606fbb -
Branch / Tag:
refs/pull/1/merge - Owner: https://github.com/abhishektiwari
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@35481f2e265d9dc27943a8daf39bd9ce43606fbb -
Trigger Event:
pull_request
-
Statement type: