SDK for verifying access tokens and securing APIs with Auth0, using Authlib.
Project description
📚 Documentation - 🚀 Getting Started - 💬 Feedback
Documentation
- QuickStart- our guide for adding Auth0 to your Fastapi app.
- Examples - examples for your different use cases.
- Docs Site - explore our docs site and learn more about Auth0.
Getting Started
1. Install the SDK
This library requires Python 3.9+.
pip install auth0-fastapi-api
If you’re using Poetry:
poetry install auth0-fastapi-api
2. Configure and Register the Auth0FastAPI Plugin
In your FastAPI application, create an instance of the Auth0FastAPI class. Supply the domain and audience from Auth0:
- The
AUTH0_DOMAINcan be obtained from the Auth0 Dashboard once you've created an API. - The
AUTH0_AUDIENCEis the identifier of the API that is being called. You can find this in the API section of the Auth0 dashboard.
from fastapi_plugin.fast_api_client import Auth0FastAPI
# Create the Auth0 integration
auth0 = Auth0FastAPI(
domain="<AUTH0_DOMAIN>",
audience="<AUTH0_AUDIENCE>",
)
DPoP Configuration (Optional)
The SDK supports DPoP (Demonstrating Proof-of-Possession) for enhanced security:
# Mixed mode - accepts both Bearer and DPoP (recommended for migration)
auth0 = Auth0FastAPI(
domain="<AUTH0_DOMAIN>",
audience="<AUTH0_AUDIENCE>",
dpop_enabled=True, # Enable DPoP support
dpop_required=False # Allow Bearer tokens too (mixed mode)
)
# DPoP-only mode - rejects Bearer tokens
auth0 = Auth0FastAPI(
domain="<AUTH0_DOMAIN>",
audience="<AUTH0_AUDIENCE>",
dpop_enabled=True,
dpop_required=True # Only accept DPoP tokens
)
# Custom DPoP timing configuration
auth0 = Auth0FastAPI(
domain="<AUTH0_DOMAIN>",
audience="<AUTH0_AUDIENCE>",
dpop_enabled=True,
dpop_iat_leeway=30, # Clock skew tolerance (seconds)
dpop_iat_offset=300 # Maximum DPoP proof age (seconds)
)
Reverse Proxy Configuration
When deploying behind a reverse proxy (nginx, AWS ALB, etc.), you must enable proxy trust for DPoP validation to work correctly:
from fastapi import FastAPI
from fastapi_plugin.fast_api_client import Auth0FastAPI
app = FastAPI()
# CRITICAL: Enable proxy trust when behind a reverse proxy
app.state.trust_proxy = True
auth0 = Auth0FastAPI(
domain="<AUTH0_DOMAIN>",
audience="<AUTH0_AUDIENCE>",
dpop_enabled=True
)
Why this matters:
- DPoP validation requires matching the exact URL the client used
- Behind a proxy, your app sees internal URLs (e.g.,
http://localhost:8000/api) - The client's DPoP proof contains the public URL (e.g.,
https://api.example.com/api) - Without
trust_proxy=True, validation will fail
Note: Only enable trust_proxy=True when your app is actually behind a trusted reverse proxy. Never enable this for direct internet-facing deployments, as it would allow header injection attacks.
Nginx Configuration Example:
location /api {
proxy_pass http://backend:8000;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Prefix /api;
}
3. Protecting API Routes
To protect a FastAPI route, use the require_auth(...) dependency. The SDK automatically detects and validates both Bearer and DPoP authentication schemes. Any incoming requests must include a valid token in the Authorization header, or they will receive an error response (e.g., 401 Unauthorized).
@app.get("/protected-api")
async def protected(
# The route depends on require_auth returning the decoded token claims
claims: dict = Depends(auth0.require_auth())
):
# `claims` is the verified JWT payload (dict) extracted by the SDK
return {"message": f"Hello, {claims['sub']}"}
How It Works
Bearer Authentication:
- The user sends a request with
Authorization: Bearer <JWT>. - The SDK parses the token, checks signature via Auth0's JWKS, validates standard claims like
iss,aud,exp, etc. - If valid, the route receives the decoded claims as a Python dict.
DPoP Authentication:
- The user sends a request with
Authorization: DPoP <JWT>andDPoP: <proof-jwt>headers. - The SDK validates both the access token and the DPoP proof, including cryptographic binding.
- DPoP provides enhanced security through proof-of-possession of private keys.
- If valid, the route receives the decoded claims as a Python dict.
The SDK automatically detects which authentication scheme is being used and validates accordingly.
[!IMPORTANT]
This method protects API endpoints using bearer tokens. It does not create or manage user sessions in server-side rendering scenarios. For session-based usage, consider a separate library or approach.
Custom Claims
If your tokens have additional custom claims, you’ll see them in the claims dictionary. For example:
@app.get("/custom")
async def custom_claims_route(claims: dict = Depends(auth0.require_auth())):
# Suppose your JWT includes { "permissions": ["read:data"] }
permissions = claims.get("permissions", [])
return {"permissions": permissions}
You can parse or validate these claims however you like in your application code.
Dependency in the path operation decorator
In case you don't need to use the claims dictionary in your endpoint you can also use the dependency as part of the path decorator. For example:
@app.get("/protected", dependencies=[Depends(auth0.require_auth())])
async def protected():
# Protected endpoint
return {"msg": "You need to have an access token to see this endpoint."}
This way you can protected your endpoint and not have an unused variable.
4. Advanced Configuration
- Scopes: If you need to check for specific scopes (like
read:data), call require_auth(scopes="read:data")or pass a list of scopes. The SDK will return a 403 if the token lacks those scopes in itsscopeclaim.
@app.get("/read-data")
async def read_data_route(
claims=Depends(auth0.require_auth(scopes="read:data"))
):
return {"data": "secret info"}
- Mocking / Testing: To test locally without hitting Auth0’s actual JWKS endpoints, you can mock the HTTP calls using
pytest-httpxor patch the verification method to avoid real cryptographic checks.
Example
from fastapi import FastAPI, Depends
from auth0_fastapi_api import Auth0FastAPI
from fastapi.testclient import TestClient
app = FastAPI()
auth0 = Auth0FastAPI(domain="my-tenant.us.auth0.com", audience="my-api")
@app.get("/public")
async def public():
return {"message": "No token required here"}
@app.get("/secure")
async def secure_route(
claims: dict = Depends(auth0.require_auth(scopes="read:secure"))
):
# claims might contain {"sub":"user123","scope":"read:secure"}
return {"message": f"Hello {claims['sub']}, you have read:secure scope!"}
# Example test
def test_public_route():
client = TestClient(app)
response = client.get("/public")
assert response.status_code == 200
assert response.json() == {"message": "No token required here"}
5. DPoP Authentication
Note: DPoP is currently in Early Access. Contact Auth0 support to enable it for your tenant.
DPoP (Demonstrating Proof-of-Possession) provides enhanced security by binding access tokens to cryptographic proof of possession.
Client Requirements
To use DPoP authentication, clients must:
- Generate an ES256 key pair for DPoP proof signing
- Include two headers in requests:
Authorization: DPoP <access-token>- The DPoP-bound access tokenDPoP: <proof-jwt>- The DPoP proof JWT
Example DPoP Request
GET /protected-api HTTP/1.1
Host: api.example.com
Authorization: DPoP eyJ0eXAiOiJKV1Q...
DPoP: eyJ0eXAiOiJkcG9wK2p3dC...
Migration Strategy
Use mixed mode for gradual migration:
# Start with mixed mode to support both Bearer and DPoP
auth0 = Auth0FastAPI(
domain="<AUTH0_DOMAIN>",
audience="<AUTH0_AUDIENCE>",
dpop_enabled=True,
dpop_required=False # Allows both Bearer and DPoP
)
# Later, enforce DPoP-only
auth0 = Auth0FastAPI(
domain="<AUTH0_DOMAIN>",
audience="<AUTH0_AUDIENCE>",
dpop_required=True # Rejects Bearer tokens
)
6. Get an access token for a connection
If you need to get an access token for an upstream idp via a connection, you can use the get_access_token_for_connection method on the underlying api_client:
import asyncio
from fastapi_plugin.fast_api_client import Auth0FastAPI
async def main():
auth0 = Auth0FastAPI(
domain="<AUTH0_DOMAIN>",
audience="<AUTH0_AUDIENCE>",
client_id="<AUTH0_CLIENT_ID>",
client_secret="<AUTH0_CLIENT_SECRET>",
)
connection = "my-connection" # The Auth0 connection to the upstream idp
access_token = "..." # The Auth0 access token to exchange
connection_access_token = await auth0.api_client.get_access_token_for_connection({"connection": connection, "access_token": access_token})
# The returned token is the access token for the upstream idp
print(connection_access_token)
asyncio.run(main())
More info https://auth0.com/docs/secure/tokens/token-vault
Feedback
Contributing
We appreciate feedback and contribution to this repo! Before you get started, please read the following:
- Auth0's general contribution guidelines
- Auth0's code of conduct guidelines
- This repo's contribution guide
Raise an issue
To provide feedback or report a bug, please raise an issue on our issue tracker.
Vulnerability Reporting
Please do not report security vulnerabilities on the public GitHub issue tracker. The Responsible Disclosure Program details the procedure for disclosing security issues.
What is Auth0?
Auth0 is an easy to implement, adaptable authentication and authorization platform. To learn more checkout Why Auth0?
This project is licensed under the MIT license. See the LICENSE file for more info.
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 auth0_fastapi_api-1.0.0b5.tar.gz.
File metadata
- Download URL: auth0_fastapi_api-1.0.0b5.tar.gz
- Upload date:
- Size: 8.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
df4806100062c072077b8fc6975864931f8da0f1c7abdbe109c8db4188910d94
|
|
| MD5 |
f5f5425a5ba31f24ccf6a398801a81f7
|
|
| BLAKE2b-256 |
cddb390775a8dc0330586316057ed51032675ca2bffdf9c22596dc70263211a7
|
Provenance
The following attestation bundles were made for auth0_fastapi_api-1.0.0b5.tar.gz:
Publisher:
publish.yml on auth0/auth0-fastapi-api
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
auth0_fastapi_api-1.0.0b5.tar.gz -
Subject digest:
df4806100062c072077b8fc6975864931f8da0f1c7abdbe109c8db4188910d94 - Sigstore transparency entry: 709995295
- Sigstore integration time:
-
Permalink:
auth0/auth0-fastapi-api@eba339fe2b0656e33aaa1f8d02030e37a5cf93a8 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/auth0
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@eba339fe2b0656e33aaa1f8d02030e37a5cf93a8 -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file auth0_fastapi_api-1.0.0b5-py3-none-any.whl.
File metadata
- Download URL: auth0_fastapi_api-1.0.0b5-py3-none-any.whl
- Upload date:
- Size: 9.7 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 |
f946128901c5a7205a348a7731323e62f661803bacb53e400069ebc48a79b295
|
|
| MD5 |
3f8a90bfd19fb563ff7b4799b6e24c44
|
|
| BLAKE2b-256 |
9b5a71fea35be1f7c1c78877ea09602f3700cf85425cfed1eee06976f5cc7cb1
|
Provenance
The following attestation bundles were made for auth0_fastapi_api-1.0.0b5-py3-none-any.whl:
Publisher:
publish.yml on auth0/auth0-fastapi-api
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
auth0_fastapi_api-1.0.0b5-py3-none-any.whl -
Subject digest:
f946128901c5a7205a348a7731323e62f661803bacb53e400069ebc48a79b295 - Sigstore transparency entry: 709995308
- Sigstore integration time:
-
Permalink:
auth0/auth0-fastapi-api@eba339fe2b0656e33aaa1f8d02030e37a5cf93a8 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/auth0
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@eba339fe2b0656e33aaa1f8d02030e37a5cf93a8 -
Trigger Event:
workflow_dispatch
-
Statement type: