This page demonstrates asynchronous usage patterns for the Auth0 Python SDK, covering the AsyncManagementClient and AsyncAuth0 clients. Topics include session management, concurrent operations, pagination, error handling, and resource cleanup. For synchronous patterns, see page 3.2. For Authentication API usage, see page 3.1.
The SDK provides async clients for both Management and Authentication APIs, using different HTTP libraries:
Title: Async Client Module Structure
Sources: README.md86-102 README.md153-180 requirements.txt1-13 CHANGELOG.md27-28
The Management API uses httpx.AsyncClient (specified in requirements.txt2), while the Authentication API uses aiohttp (version >=3.10.11 in requirements.txt8). Both provide async/await support introduced in v5.0.0 (CHANGELOG.md27-28).
The auth0.management.AsyncManagementClient class supports two initialization modes: token-based and credential-based with automatic token management.
Title: AsyncManagementClient Initialization Modes
Token-Based Initialization:
See README.md92-95 for example. The AsyncManagementClient is initialized with domain and token parameters:
from auth0.management import AsyncManagementClient
client = AsyncManagementClient(
domain="your-tenant.auth0.com",
token="YOUR_EXISTING_TOKEN",
)
Credential-Based Initialization:
Automatic token management is enabled when providing client_id and client_secret. The client handles token acquisition and refresh transparently:
client = AsyncManagementClient(
domain="your-tenant.auth0.com",
client_id="YOUR_CLIENT_ID",
client_secret="YOUR_CLIENT_SECRET",
)
This feature was added in v5.0.0 (CHANGELOG.md28).
Sources: README.md86-102 CHANGELOG.md28
The auth0.management.AsyncAuth0 class provides lower-level access to the Management API, requiring a full base_url parameter instead of just domain.
Title: AsyncAuth0 Client Initialization and Sub-Clients
Example from README.md161-177:
from auth0.management import AsyncAuth0, ActionTrigger
client = AsyncAuth0(
base_url="https://YOUR_TENANT.auth0.com/api/v2",
token="YOUR_TOKEN",
)
async def create_action():
result = await client.actions.create(
name="my-action",
supported_triggers=[ActionTrigger(id="post-login")],
)
return result
The AsyncAuth0 class follows the modular sub-client architecture introduced in v5.0.0 (CHANGELOG.md18).
Sources: README.md153-180 CHANGELOG.md18
The Management API async clients accept an httpx_client parameter to share a connection pool across multiple client instances. This improves performance by reusing TCP connections.
Title: Shared httpx.AsyncClient Pattern
Example pattern from README.md304-316:
import httpx
from auth0.management import AsyncManagementClient
async def main():
async with httpx.AsyncClient() as session:
client1 = AsyncManagementClient(
domain="your-tenant.auth0.com",
token="TOKEN_1",
httpx_client=session,
)
client2 = AsyncManagementClient(
domain="your-tenant.auth0.com",
token="TOKEN_2",
httpx_client=session,
)
users = await client1.users.list()
orgs = await client2.organizations.list()
Note: For Management API clients, use httpx.AsyncClient(). The Authentication API uses aiohttp.ClientSession instead (requirements.txt2-8).
Sources: README.md299-316 requirements.txt2 requirements.txt8
Async clients enable parallel API requests using asyncio.gather() or asyncio.create_task().
Title: Sequential vs Concurrent Request Patterns
Execute multiple independent API calls concurrently:
import asyncio
from auth0.management import AsyncManagementClient
async def fetch_data():
client = AsyncManagementClient(
domain="your-tenant.auth0.com",
token="YOUR_TOKEN",
)
users, orgs, clients = await asyncio.gather(
client.users.list(),
client.organizations.list(),
client.clients.list(),
)
return users, orgs, clients
Create tasks for finer control over execution timing:
async def background_operations():
client = AsyncManagementClient(
domain="your-tenant.auth0.com",
token="YOUR_TOKEN",
)
task1 = asyncio.create_task(client.users.list())
task2 = asyncio.create_task(client.organizations.list())
await process_something_else()
users = await task1
orgs = await task2
Limit concurrent requests to avoid rate limits:
async def batch_update_users(user_ids: list[str]):
client = AsyncManagementClient(
domain="your-tenant.auth0.com",
token="YOUR_TOKEN",
)
semaphore = asyncio.Semaphore(5)
async def update_user(user_id: str):
async with semaphore:
await client.users.update(
id=user_id,
body={"user_metadata": {"updated": True}}
)
await asyncio.gather(*[update_user(uid) for uid in user_ids])
This prevents overwhelming the API with concurrent requests, staying within rate limits documented in page 2.3.2.
Sources: README.md86-102
Paginated Management API list operations return auth0.management.core.paginators.AsyncPager[T], supporting async iteration over items or pages.
Title: AsyncPager Iteration Methods
Process individual items across all pages:
async def process_all_users():
client = AsyncManagementClient(
domain="your-tenant.auth0.com",
token="YOUR_TOKEN",
)
pager = await client.users.list()
async for user in pager:
print(f"User: {user.email}")
Process pages with access to pagination metadata:
async def process_by_pages():
client = AsyncManagementClient(
domain="your-tenant.auth0.com",
token="YOUR_TOKEN",
)
pager = await client.users.list(per_page=50)
async for page in pager.iter_pages():
print(f"Processing page with {len(page.response.users)} users")
async for user in page:
print(f" - {user.email}")
The .response attribute provides access to the typed response object:
async def check_pagination_info():
client = AsyncManagementClient(
domain="your-tenant.auth0.com",
token="YOUR_TOKEN",
)
pager = await client.users.list()
first_page_response = pager.response
print(f"Total users: {first_page_response.total}")
async for page in pager.iter_pages():
print(f"Page response: {page.response}")
Example from README.md224-230 shows page-level access. Default pagination behavior with include_totals=True was changed in v5.0.0 (CHANGELOG.md22).
Sources: README.md197-257 README.md224-230 CHANGELOG.md22-23
The auth0.management.core.api_error.ApiError exception class is raised for 4xx and 5xx responses in both sync and async contexts.
Title: ApiError Exception Flow
Example from README.md187-195:
from auth0.management.core.api_error import ApiError
from auth0.management import AsyncManagementClient
async def safe_user_creation():
client = AsyncManagementClient(
domain="your-tenant.auth0.com",
token="YOUR_TOKEN",
)
try:
user = await client.users.create(
email="user@example.com",
connection="Username-Password-Authentication",
)
return user
except ApiError as e:
print(f"API Error {e.status_code}: {e.body}")
raise
Handle HTTP 429 responses with exponential backoff:
import asyncio
async def create_user_with_retry(max_attempts: int = 3):
client = AsyncManagementClient(
domain="your-tenant.auth0.com",
token="YOUR_TOKEN",
)
for attempt in range(max_attempts):
try:
return await client.users.create(
email="user@example.com",
connection="Username-Password-Authentication",
)
except ApiError as e:
if e.status_code == 429 and attempt < max_attempts - 1:
wait_time = 2 ** attempt
await asyncio.sleep(wait_time)
continue
raise
The SDK includes automatic retry logic for 408, 429, and 5xx status codes (README.md260-277). See page 2.3.2 for rate limiting details.
Sources: README.md182-195 README.md260-277 CHANGELOG.md21
The auth0.authentication module supports async operations. Note that the Authentication API uses aiohttp.ClientSession (not httpx).
Title: Authentication API Async Client Stack
The GetToken class supports async methods:
from auth0.authentication import GetToken
async def get_token():
token_client = GetToken(
domain="your-tenant.auth0.com",
client_id="YOUR_CLIENT_ID",
client_secret="YOUR_CLIENT_SECRET",
)
token = await token_client.client_credentials(
audience="https://your-tenant.auth0.com/api/v2/"
)
return token["access_token"]
Session sharing for the Authentication API uses aiohttp.ClientSession:
import aiohttp
async def shared_auth_session():
async with aiohttp.ClientSession() as session:
# Session sharing implementation depends on rest_async.py internals
# Refer to auth0.authentication module documentation
pass
The Authentication API was made async-capable in v3.24.0 (CHANGELOG.md235-236). It uses aiohttp>=3.10.11 (requirements.txt8).
Sources: requirements.txt8 CHANGELOG.md235-236
Async HTTP clients must be explicitly closed to prevent connection leaks. Use async with statements or manual cleanup in finally blocks.
Title: Resource Lifecycle Management
Use try/finally for explicit resource management:
import httpx
from auth0.management import AsyncManagementClient
async def manual_cleanup():
session = httpx.AsyncClient()
try:
client = AsyncManagementClient(
domain="your-tenant.auth0.com",
token="YOUR_TOKEN",
httpx_client=session,
)
users = await client.users.list()
return users
finally:
await session.aclose()
The async with statement guarantees cleanup:
async def with_context_manager():
async with httpx.AsyncClient() as session:
client = AsyncManagementClient(
domain="your-tenant.auth0.com",
token="YOUR_TOKEN",
httpx_client=session,
)
users = await client.users.list()
return users
Example from README.md304-316 For aiohttp.ClientSession (Authentication API), use the same pattern with async with aiohttp.ClientSession().
Sources: README.md299-316
This example combines session sharing, concurrent operations, pagination, rate limiting, and error handling:
import asyncio
import httpx
from auth0.management import AsyncManagementClient
from auth0.management.core.api_error import ApiError
async def fetch_user_data(client: AsyncManagementClient, user_id: str):
"""Fetch user with error handling."""
try:
return await client.users.get(id=user_id)
except ApiError as e:
print(f"Failed to fetch user {user_id}: {e.status_code}")
return None
async def main():
# Shared httpx.AsyncClient for connection pooling
async with httpx.AsyncClient() as session:
client = AsyncManagementClient(
domain="your-tenant.auth0.com",
token="YOUR_TOKEN",
httpx_client=session,
)
# Concurrent list operations
users_pager, orgs_pager = await asyncio.gather(
client.users.list(per_page=100),
client.organizations.list(),
)
# Process paginated results
user_ids = []
async for user in users_pager:
user_ids.append(user.user_id)
# Batch fetch with rate limiting (max 10 concurrent)
semaphore = asyncio.Semaphore(10)
async def fetch_with_limit(uid: str):
async with semaphore:
return await fetch_user_data(client, uid)
detailed_users = await asyncio.gather(
*[fetch_with_limit(uid) for uid in user_ids[:50]]
)
# Filter out failed fetches
successful_users = [u for u in detailed_users if u is not None]
print(f"Successfully fetched {len(successful_users)} users")
if __name__ == "__main__":
asyncio.run(main())
Pattern Summary:
httpx.AsyncClient for all operationsasyncio.gather() for parallel list operationsasync for over AsyncPager objectsasyncio.Semaphore(10) limits concurrent user fetchestry/except ApiError in helper functionasync with ensures session closureSources: README.md86-102 README.md153-180 README.md182-195
| Practice | Description | Code Pattern |
|---|---|---|
| Use Context Managers | Always use async with for sessions | async with httpx.AsyncClient() as session: |
| Share Sessions | Reuse HTTP clients across multiple operations | Pass httpx_client=session to clients |
| Limit Concurrency | Use asyncio.Semaphore to control concurrent requests | async with asyncio.Semaphore(10): |
| Handle Rate Limits | Catch ApiError with status 429 and implement backoff | if e.status_code == 429: await asyncio.sleep(...) |
| Use gather() for Parallel | Execute independent operations concurrently | await asyncio.gather(op1(), op2()) |
| Iterate Pagers Properly | Use async for with pagers | async for item in pager: |
| Clean Up Resources | Always close sessions and clients | await session.aclose() or use context managers |
Sources: README.md86-102 README.md153-180 README.md299-316 CHANGELOG.md19-26
Refresh this wiki