SDK for verifying access tokens and securing APIs with Auth0, using Authlib.
Project description
The auth0-api-python library allows you to secure APIs running on Python, particularly for verifying Auth0-issued access tokens.
It’s intended as a foundation for building more framework-specific integrations (e.g., with FastAPI, Django, etc.), but you can also use it directly in any Python server-side environment.
📚 Documentation - 🚀 Getting Started - 💬 Feedback
Features & Authentication Schemes
This SDK provides comprehensive support for securing APIs with Auth0-issued access tokens:
Authentication Schemes
- Bearer Token Authentication - Traditional OAuth 2.0 Bearer tokens (RS256)
- DPoP Authentication - Enhanced security with Demonstrating Proof-of-Possession (ES256)
- Mixed Mode Support - Seamlessly handles both Bearer and DPoP in the same API
Core Features
- Unified Entry Point:
verify_request()- automatically detects and validates Bearer or DPoP schemes - Multi-Custom Domain (MCD) - Accept tokens from multiple Auth0 domains with static lists or dynamic resolvers
- OIDC Discovery - Automatic fetching of Auth0 metadata and JWKS with per-issuer caching
- JWT Validation - Complete RS256 signature verification with claim validation
- DPoP Proof Verification - Full RFC 9449 compliance with ES256 signature validation
- Flexible Configuration - Support for both "Allowed" and "Required" DPoP modes
- Comprehensive Error Handling - Detailed errors with proper HTTP status codes and WWW-Authenticate headers
- Framework Agnostic - Works with FastAPI, Django, Flask, or any Python web framework
Documentation
- Docs Site - explore our docs site and learn more about Auth0.
Related SDKs
This library is part of Auth0's Python ecosystem for server-side authentication and API security. Related SDKs:
- auth0-auth-js - JavaScript/TypeScript monorepo containing:
@auth0/auth0-auth-js- Core authentication client (low-level primitives)@auth0/auth0-api-js- Server-side API security (Node.js equivalent of this library)@auth0/auth0-server-js- Server-side web app authentication (session management)
Getting Started
1. Install the SDK
This library requires Python 3.9+.
pip install auth0-api-python
If you’re using Poetry:
poetry install auth0-api-python
2. Create the Auth0 SDK client
Create an instance of the ApiClient. This instance will be imported and used anywhere we need access to the methods.
from auth0_api_python import ApiClient, ApiClientOptions
api_client = ApiClient(ApiClientOptions(
domain="<AUTH0_DOMAIN>",
audience="<AUTH0_AUDIENCE>"
))
- The
AUTH0_DOMAINcan be obtained from the Auth0 Dashboard once you've created an application. - The
AUTH0_AUDIENCEis the identifier of the API. You can find this in the APIs section of the Auth0 Dashboard.
3. Verify the Access Token
Use the verify_access_token method to validate access tokens. The method automatically checks critical claims like iss, aud, exp, nbf.
import asyncio
from auth0_api_python import ApiClient, ApiClientOptions
async def main():
api_client = ApiClient(ApiClientOptions(
domain="<AUTH0_DOMAIN>",
audience="<AUTH0_AUDIENCE>"
))
access_token = "..."
decoded_and_verified_token = await api_client.verify_access_token(access_token=access_token)
print(decoded_and_verified_token)
asyncio.run(main())
In this example, the returned dictionary contains the decoded claims (like sub, scope, etc.) from the verified token.
4. 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:
import asyncio
from auth0_api_python import ApiClient, ApiClientOptions
async def main():
api_client = ApiClient(ApiClientOptions(
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 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
5. Custom Token Exchange (Early Access)
[!NOTE] This feature is currently available in Early Access for Enterprise customers. Please reach out to Auth0 support to get it enabled for your tenant.
This feature requires a confidential client (both client_id and client_secret must be configured).
Custom Token Exchange allows you to exchange a subject token for Auth0 tokens using RFC 8693. This is useful for:
- Getting Auth0 tokens for another audience
- Integrating external identity providers
- Migrating to Auth0
import asyncio
from auth0_api_python import ApiClient, ApiClientOptions
async def main():
api_client = ApiClient(ApiClientOptions(
domain="<AUTH0_DOMAIN>",
audience="<AUTH0_AUDIENCE>",
client_id="<AUTH0_CLIENT_ID>",
client_secret="<AUTH0_CLIENT_SECRET>",
timeout=10.0 # Optional: HTTP timeout in seconds (default: 10.0)
))
subject_token = "..." # Token from your legacy system or external source
result = await api_client.get_token_by_exchange_profile(
subject_token=subject_token,
subject_token_type="urn:example:subject-token",
audience="https://api.example.com", # Optional - omit if your Action or tenant configuration sets the audience
scope="openid profile email", # Optional
requested_token_type="urn:ietf:params:oauth:token-type:access_token" # Optional
)
# Result contains access_token, expires_in, expires_at
# id_token, refresh_token, and scope are profile/Action dependent (not guaranteed; scope may be empty)
asyncio.run(main())
Important:
- Client authentication is sent via HTTP Basic (
client_id/client_secret), not in the form body. - Do not prefix
subject_tokenwith "Bearer " - send the raw token value only (checked case-insensitively). - The
subject_token_typemust match a Token Exchange Profile configured in Auth0. This URI identifies which profile will process the exchange and must not use reserved OAuth namespaces (IETF or vendor-controlled). Use your own collision-resistant namespace. See the Custom Token Exchange documentation for naming guidance. - If neither an explicit
audiencenor tenant/Action logic sets it, you may receive a token not targeted at your API.
Additional Parameters
You can pass additional parameters for your Token Exchange Profile or Actions via the extra parameter. These are sent as form fields to Auth0 and may be inspected by Actions:
result = await api_client.get_token_by_exchange_profile(
subject_token=subject_token,
subject_token_type="urn:example:subject-token",
audience="https://api.example.com",
extra={
"device_id": "device-12345",
"session_id": "sess-abc"
}
)
[!WARNING] Extra parameters are sent as form fields and may appear in logs. Do not include secrets or sensitive data. Reserved OAuth parameter names (like
grant_type,client_id,scope) cannot be used and will raise an error. Arrays are supported but limited to 20 values per key to prevent abuse.
Error Handling
from auth0_api_python import GetTokenByExchangeProfileError, ApiError
try:
result = await api_client.get_token_by_exchange_profile(
subject_token=subject_token,
subject_token_type="urn:example:subject-token"
)
except GetTokenByExchangeProfileError as e:
# Validation errors (invalid token format, missing credentials, reserved params, etc.)
print(f"Validation error: {e}")
except ApiError as e:
# Token endpoint errors (invalid_grant, network issues, malformed responses, etc.)
print(f"API error: {e.code} - {e.message} (status: {e.status_code})")
Related SDKs: auth0-auth-js (see @auth0/auth0-api-js package for Node.js equivalent)
More info: https://auth0.com/docs/authenticate/custom-token-exchange
Requiring Additional Claims
If your application demands extra claims, specify them with required_claims:
decoded_and_verified_token = await api_client.verify_access_token(
access_token=access_token,
required_claims=["my_custom_claim"]
)
If the token lacks my_custom_claim or fails any standard check (issuer mismatch, expired token, invalid signature), the method raises a VerifyAccessTokenError.
6. DPoP Authentication
This library supports DPoP (Demonstrating Proof-of-Possession) for enhanced security, allowing clients to prove possession of private keys bound to access tokens.
Allowed Mode (Default)
Accepts both Bearer and DPoP tokens - ideal for gradual migration:
api_client = ApiClient(ApiClientOptions(
domain="<AUTH0_DOMAIN>",
audience="<AUTH0_AUDIENCE>",
dpop_enabled=True, # Default - enables DPoP support
dpop_required=False # Default - allows both Bearer and DPoP
))
# Use verify_request() for automatic scheme detection
result = await api_client.verify_request(
headers={
"authorization": "DPoP eyJ0eXAiOiJKV1Q...", # DPoP scheme
"dpop": "eyJ0eXAiOiJkcG9wK2p3dC...", # DPoP proof
},
http_method="GET",
http_url="https://api.example.com/resource"
)
Required Mode
Enforces DPoP-only authentication, rejecting Bearer tokens:
api_client = ApiClient(ApiClientOptions(
domain="<AUTH0_DOMAIN>",
audience="<AUTH0_AUDIENCE>",
dpop_required=True # Rejects Bearer tokens
))
Configuration Options
api_client = ApiClient(ApiClientOptions(
domain="<AUTH0_DOMAIN>",
audience="<AUTH0_AUDIENCE>",
dpop_enabled=True, # Enable/disable DPoP support
dpop_required=False, # Require DPoP (reject Bearer)
dpop_iat_leeway=30, # Clock skew tolerance (seconds)
dpop_iat_offset=300, # Maximum proof age (seconds)
))
7. Multi-Custom Domain (MCD) Support
If your Auth0 tenant has multiple custom domains, or you're migrating between domains, the SDK can accept tokens from any of them:
Static Domain List
from auth0_api_python import ApiClient, ApiClientOptions
api_client = ApiClient(ApiClientOptions(
domains=[
"tenant.auth0.com",
"auth.example.com",
"auth.acme.org"
],
audience="https://api.example.com"
))
# Tokens from any of the three domains are accepted
claims = await api_client.verify_access_token(access_token)
Dynamic Resolver
For runtime domain resolution based on request context:
from auth0_api_python import ApiClient, ApiClientOptions, DomainsResolverContext
def resolve_domains(context: DomainsResolverContext) -> list[str]:
# Determine allowed domains based on the request
return ["tenant.auth0.com", "auth.example.com"]
api_client = ApiClient(ApiClientOptions(
domains=resolve_domains,
audience="https://api.example.com"
))
For hybrid mode (migration scenarios), resolver patterns, error handling, and caching configuration, see the full guides:
- Multi-Custom Domain Guide - Configuration modes, resolver patterns, migration, error handling
- Caching Guide - Cache tuning, custom adapters (Redis, Memcached)
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_api_python-1.0.0b8.tar.gz.
File metadata
- Download URL: auth0_api_python-1.0.0b8.tar.gz
- Upload date:
- Size: 30.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fa75819756f750159b47071d8b322badcc6768b94197ce63279fbf6399be6c32
|
|
| MD5 |
f46fda7311d71ccd626ff2cd4cdae302
|
|
| BLAKE2b-256 |
ff7cc9219eddac8378ba2e47dbd3b2f6d02d66ab061f8c26b72ac2a10934d1d1
|
Provenance
The following attestation bundles were made for auth0_api_python-1.0.0b8.tar.gz:
Publisher:
publish.yml on auth0/auth0-api-python
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
auth0_api_python-1.0.0b8.tar.gz -
Subject digest:
fa75819756f750159b47071d8b322badcc6768b94197ce63279fbf6399be6c32 - Sigstore transparency entry: 1262718492
- Sigstore integration time:
-
Permalink:
auth0/auth0-api-python@cca3b25eeddf9e55febd5c575bab5617e0ee710a -
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@cca3b25eeddf9e55febd5c575bab5617e0ee710a -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file auth0_api_python-1.0.0b8-py3-none-any.whl.
File metadata
- Download URL: auth0_api_python-1.0.0b8-py3-none-any.whl
- Upload date:
- Size: 29.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1ff8baff727e7aa2b4f89ec41b3642f8b4e0206e1af7f3a69acc318f260fd5dc
|
|
| MD5 |
c79a422d7f675f28fcd700fcceed1478
|
|
| BLAKE2b-256 |
0941bbf283faa8abca01c8eaf384a747f20dddcd35b878865a9feae5947dae28
|
Provenance
The following attestation bundles were made for auth0_api_python-1.0.0b8-py3-none-any.whl:
Publisher:
publish.yml on auth0/auth0-api-python
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
auth0_api_python-1.0.0b8-py3-none-any.whl -
Subject digest:
1ff8baff727e7aa2b4f89ec41b3642f8b4e0206e1af7f3a69acc318f260fd5dc - Sigstore transparency entry: 1262718591
- Sigstore integration time:
-
Permalink:
auth0/auth0-api-python@cca3b25eeddf9e55febd5c575bab5617e0ee710a -
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@cca3b25eeddf9e55febd5c575bab5617e0ee710a -
Trigger Event:
workflow_dispatch
-
Statement type: