Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
307 changes: 150 additions & 157 deletions src/content/docs/developer-tools/sdks/backend/python-sdk.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -1386,239 +1386,232 @@ You don't need to manually manage tokens or sessions - the SDK handles this auto

## Management API

The Kinde Python SDK provides a Management API client for interacting with Kinde's management endpoints. This allows you to programmatically manage users, organizations, and other resources. The Management API supports both sync and async patterns.
The Kinde Python SDK includes a separate Management API client for interacting with Kinde's management endpoints. This allows you to programmatically manage users, organizations, roles, permissions, feature flags, and other resources.

### Getting started
The Management API client is independent of the OAuth authentication clients (`OAuth`, `AsyncOAuth`, `SmartOAuth`). You initialize it directly with your management API credentials.

#### With OAuth client (Framework-based)
### Getting started

```python
from kinde_sdk.auth.oauth import OAuth
from flask import Flask
import asyncio
from kinde_sdk.management.management_client import ManagementClient

app = Flask(__name__)
oauth = OAuth(framework="flask", app=app)
management = ManagementClient(
domain="your-domain.kinde.com",
client_id="your-management-client-id",
client_secret="your-management-client-secret"
)
```

# Get the management client
management = oauth.get_management()
You can also load credentials from a `.env` file. This requires the `python-dotenv` package:

# Use with asyncio in Flask
def list_users_sync():
loop = asyncio.get_event_loop()
users = loop.run_until_complete(management.get_users())
return users
```bash
pip install python-dotenv
```

#### With AsyncOAuth client (Native async)
Call `load_dotenv()` before initializing `ManagementClient` so the environment variables are available:

```python
from kinde_sdk.auth.async_oauth import AsyncOAuth

oauth = AsyncOAuth()
import os
from dotenv import load_dotenv
from kinde_sdk.management.management_client import ManagementClient

# Get the management client (native async)
management = await oauth.get_management()
load_dotenv()
Comment thread
coderabbitai[bot] marked this conversation as resolved.

# All methods are async
users = await management.get_users()
management = ManagementClient(
domain=os.getenv("KINDE_HOST", "").replace("https://", ""),
client_id=os.getenv("MGMT_API_CLIENT_ID"),
client_secret=os.getenv("MGMT_API_CLIENT_SECRET")
)
Comment thread
Koosha-Owji marked this conversation as resolved.
```

#### With SmartOAuth client (Context-aware)
### Available endpoints

The `ManagementClient` dynamically discovers all auto-generated API classes and exposes them as snake_case properties. Access endpoints through these API class properties:

**User management:**

```python
from kinde_sdk.auth.smart_oauth import SmartOAuth
# List users
users = management.users_api.get_users(page_size=10)

# Get a specific user
user = management.users_api.get_user_data(id="user_123")

# Create a new user
new_user = management.users_api.create_user(
create_user_request={
"profile": {
"given_name": "John",
"family_name": "Doe"
},
"identities": [{
"type": "email",
"details": {"email": "user@example.com"}
}]
}
)

oauth = SmartOAuth()
# Update a user
management.users_api.update_user(
id="user_123",
update_user_request={"given_name": "Johnny"}
)

# Works in async context
async def async_get_users():
management = await oauth.get_management()
return await management.get_users()

# Works in sync context (if supported)
def sync_get_users():
management = oauth.get_management()
return management.get_users()
# Delete a user
management.users_api.delete_user(id="user_123")
```

### Available endpoints
**Other common API classes:**

The Management API provides methods for common operations on resources. All examples use async patterns:
```python
management.organizations_api # Organization management
management.roles_api # Role management
management.permissions_api # Permission management
management.feature_flags_api # Feature flag management
management.applications_api # Application management
management.subscribers_api # Subscriber management
management.connections_api # Connection management
management.webhooks_api # Webhook management
```

**User management:**
When new API classes are added to the generated module, they are automatically available on the client without any code changes.

### Organization management

```python
# List users (async)
users = await management.get_users()
from kinde_sdk.management.management_client import ManagementClient

management = ManagementClient(
domain="your-domain.kinde.com",
client_id="your-management-client-id",
client_secret="your-management-client-secret"
)

# Get a specific user (async)
user = await management.get_user(user_id="user_123")
# List organizations
orgs = management.organizations_api.get_organizations(page_size=10)

# Create a new user (async)
new_user = await management.create_user(
email="user@example.com",
given_name="John",
family_name="Doe"
# Get a specific organization
org = management.organizations_api.get_organization(code="org_1234")

# Create a new organization
new_org = management.organizations_api.create_organization(
create_organization_request={"name": "My Organization"}
)

# Update a user (async)
updated_user = await management.update_user(
user_id="user_123",
given_name="Johnny"
# Update an organization
management.organizations_api.update_organization(
org_code="org_1234",
update_organization_request={"name": "Updated Name"}
)

# Delete a user (async)
await management.delete_user(user_id="user_123")
# Delete an organization
management.organizations_api.delete_organization(org_code="org_1234")
Comment thread
coderabbitai[bot] marked this conversation as resolved.
```

### Organization management
Note: `get_organization` accepts `code`, while `update_organization` and `delete_organization` expect `org_code`. If you're copy-pasting between calls, update the parameter name accordingly.

**Using Management API with FastAPI (OAuth client):**
**Using the Management API in a FastAPI application:**

```python
from fastapi import FastAPI, HTTPException
from kinde_sdk.auth.oauth import OAuth
from kinde_sdk.management.management_client import ManagementClient

app = FastAPI()
oauth = OAuth(framework="fastapi", app=app)
management = ManagementClient(
domain="your-domain.kinde.com",
client_id="your-management-client-id",
client_secret="your-management-client-secret"
)

@app.get("/organizations")
async def list_organizations():
management = oauth.get_management()
orgs = await management.get_organizations()
def list_organizations():
orgs = management.organizations_api.get_organizations()
return orgs

@app.get("/organizations/{org_id}")
async def get_organization(org_id: str):
management = oauth.get_management()
org = await management.get_organization(org_id=org_id)
@app.get("/organizations/{org_code}")
def get_organization(org_code: str):
org = management.organizations_api.get_organization(code=org_code)
return org

@app.post("/organizations")
async def create_organization(name: str):
management = oauth.get_management()
new_org = await management.create_organization(name=name)
return new_org

@app.put("/organizations/{org_id}")
async def update_organization(org_id: str, name: str):
management = oauth.get_management()
updated_org = await management.update_organization(
org_id=org_id,
name=name
def create_organization(name: str):
new_org = management.organizations_api.create_organization(
create_organization_request={"name": name}
)
return updated_org
return new_org

@app.delete("/organizations/{org_id}")
async def delete_organization(org_id: str):
management = oauth.get_management()
await management.delete_organization(org_id=org_id)
@app.delete("/organizations/{org_code}")
def delete_organization(org_code: str):
management.organizations_api.delete_organization(org_code=org_code)
return {"message": "Organization deleted"}
```

**Using Management API with AsyncOAuth client:**
### Error handling

The Management API methods raise exceptions for HTTP errors. Wrap calls in try/except blocks:

```python
from kinde_sdk.auth.async_oauth import AsyncOAuth
from kinde_sdk.management.management_client import ManagementClient

oauth = AsyncOAuth()
management = ManagementClient(
domain="your-domain.kinde.com",
client_id="your-management-client-id",
client_secret="your-management-client-secret"
)

async def manage_organizations():
# Get management client
management = await oauth.get_management()

# List organizations
orgs = await management.get_organizations()

# Get a specific organization
org = await management.get_organization(org_id="org_123")

# Create a new organization
new_org = await management.create_organization(
name="My Organization"
)

# Update an organization
updated_org = await management.update_organization(
org_id="org_123",
name="Updated Name"
)

# Delete an organization
await management.delete_organization(org_id="org_123")

return orgs
try:
user = management.users_api.get_user_data(id="user_123")
except Exception as e:
print(f"Error: {e}")
```

### Error handling

The Management API methods will raise exceptions for API errors. It's recommended to handle these appropriately:

**Example with OAuth client (FastAPI):**
**In a FastAPI application:**

```python
import logging
from fastapi import FastAPI, HTTPException
from kinde_sdk.auth.oauth import OAuth
from kinde_sdk.exceptions import KindeAPIException
from kinde_sdk.management.management_client import ManagementClient
from kinde_sdk.management.exceptions import ApiException

logger = logging.getLogger(__name__)

app = FastAPI()
oauth = OAuth(framework="fastapi", app=app)
management = ManagementClient(
domain="your-domain.kinde.com",
client_id="your-management-client-id",
client_secret="your-management-client-secret"
)

@app.get("/users/{user_id}")
async def get_user(user_id: str):
management = oauth.get_management()
try:
user = await management.get_user(user_id=user_id)
return user
except KindeAPIException as e:
raise HTTPException(status_code=e.status_code, detail=str(e))
except Exception as e:
raise HTTPException(status_code=500, detail=f"Internal error: {str(e)}")
```

**Example with AsyncOAuth client:**

```python
from kinde_sdk.auth.async_oauth import AsyncOAuth
from kinde_sdk.exceptions import KindeAPIException

oauth = AsyncOAuth()

async def get_user_safely(user_id: str):
management = await oauth.get_management()
def get_user(user_id: str):
try:
user = await management.get_user(user_id=user_id)
return user
except KindeAPIException as e:
print(f"API Error {e.status_code}: {e.message}")
return None
return management.users_api.get_user_data(id=user_id)
except ApiException as e:
logger.error("Kinde API error: %s %s", e.status, e.body)
raise HTTPException(status_code=e.status, detail="Failed to fetch user")
except Exception as e:
print(f"Unexpected error: {str(e)}")
return None
logger.exception("Unexpected error fetching user %s", user_id)
raise HTTPException(status_code=500, detail="Internal server error")
```
Comment thread
coderabbitai[bot] marked this conversation as resolved.

### Token management

The Management API client has its own token management system for API authentication, which is separate from the core SDK's user session token management. The Management API client automatically handles:
The `ManagementClient` has its own token management system that is separate from the OAuth authentication clients. It uses the OAuth2 client credentials flow and automatically handles:

- **accessing Kinde Management API endpoints**: Obtains tokens for accessing Kinde's management endpoints
- **Token refresh**: Automatically refreshes management API tokens when they expire
- **Token storage**: Securely stores management API tokens
- **Thread safety**: Ensures thread-safe token handling for concurrent requests
- **Token acquisition**: Obtains tokens using a client credentials grant on the first API call
- **Token caching**: Tokens are cached and reused to avoid unnecessary requests
- **Automatic re-acquisition**: Requests new tokens via a client credentials grant when existing ones expire; token lifetime is configurable per application in the Kinde portal
- **Shared tokens**: Multiple `ManagementClient` instances with the same domain and client ID share the same token

You don't need to manually manage Management API tokens - the client handles this for you. This is different from the core SDK's user session token management, which handles user authentication tokens automatically.
You don't need to manually manage tokens -- the client handles this for you. Note that credentials are validated on the first API call, not during client initialization. If your credentials are incorrect, the error will surface when you make your first request.
Comment thread
coderabbitai[bot] marked this conversation as resolved.

### Best practices

1. **Always use async/await when calling Management API methods**: The Management API is async-native for better performance
2. **Handle API errors appropriately**: Use try/except blocks and handle `KindeAPIException` specifically
1. **Use the API class properties**: Always use `management.users_api`, `management.organizations_api`, etc. The top-level convenience methods (e.g. `management.get_users()`) are deprecated
2. **Handle API errors appropriately**: Use try/except blocks for all Management API calls
3. **Cache results when appropriate**: Reduce API calls by caching user data, organizations, and permissions
4. **Use appropriate error handling for production**: Implement logging, monitoring, and graceful error recovery
5. **Keep your client credentials secure**: Use environment variables, never commit secrets to version control
6. **Use connection pooling**: For high-traffic applications, configure HTTP connection pooling
7. **Implement retry logic**: Add retry logic with exponential backoff for transient failures
8. **Monitor token expiration**: Handle token refresh gracefully to avoid authentication failures
4. **Keep your client credentials secure**: Use environment variables, never commit secrets to version control
5. **Implement retry logic**: Add retry logic with exponential backoff for transient failures

For more information about the Management API endpoints and capabilities, see the [Kinde Management API documentation](https://docs.kinde.com/kinde-apis/management/).

Expand Down
Loading