Skip to content
Merged
Show file tree
Hide file tree
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
113 changes: 99 additions & 14 deletions packages/asgardeo-ai/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@

Python SDK for Asgardeo AI agent authentication and on-behalf-of (OBO) token flows.



## Features
- **Agent Authentication**: Authenticate AI agents using agent credentials
- **On-Behalf-Of (OBO) Tokens**: Get user tokens on behalf of authenticated agents
- **Async/Await Support**: Full async implementation using httpx
- **Token Management**: Handle token exchange, refresh, and revocation
- **Authorization URLs**: Generate authorization URLs for user authentication flows

- **Agent Authentication**: Authenticate AI agents using native auth (username/password + PKCE).
- **Organization Token Switching**: Switch tokens into child organization contexts.
- **On-Behalf-Of (OBO) Tokens**: Get user tokens delegated to the agent via auth-code or CIBA.
- **CIBA Push Authentication**: Push auth requests to users' devices and poll until approved.
- **Async/Await Support**: Full async implementation using httpx.
- **Token Management**: Handle token exchange, refresh, and revocation.
- **Authorization URLs**: Generate standard, PKCE, and organization authorization URLs.

## Installation

Expand Down Expand Up @@ -70,13 +71,69 @@ async def user_auth_flow():
auth_url, state = auth_manager.get_authorization_url(scopes)

print(f"Redirect user to: {auth_url}")

# After user authorizes and you receive the auth code:
# auth_code = "received_from_callback"

auth_code = "received_from_callback"
agent_token = await auth_manager.get_agent_token(["openid"])

# Get OBO token for the user
obo_token = await auth_manager.get_obo_token(auth_code, scopes, agent_token)
# print(f"User access token: {obo_token.access_token}")
print(f"User access token: {obo_token.access_token}")
```

### Child Organization User Authorization Flow

```python
async def child_org_user_auth_flow():
async with AgentAuthManager(config, agent_config) as auth_manager:
# 1. Get an agent token for the child organization
org_agent_token = await auth_manager.get_organization_agent_token(
switching_organization="org-uuid-here",
org_scopes=["openid", "internal_org_user_mgt_view"],
)

# 2. Build an authorization URL scoped to the child organization
scopes = ["openid", "profile", "email"]
auth_url, state = auth_manager.get_org_authorization_url(
scopes=scopes,
org_discovery_type="orgID",
discovery_value="org-uuid-here",
)
print(f"Redirect user to: {auth_url}")

# 3. After user authorizes, receive the auth code from the callback
auth_code = "received_from_callback"

# 4. Exchange the auth code for an OBO token delegated to the agent
obo_token = await auth_manager.get_obo_token(auth_code, scopes, org_agent_token)
print(f"Org-scoped user access token: {obo_token.access_token}")
```

### Organization Agent Authentication

```python
async def org_agent_flow():
async with AgentAuthManager(config, agent_config) as auth_manager:
# Authenticate as agent and switch into a child organization in one call.
org_token = await auth_manager.get_organization_agent_token(
switching_organization="org-uuid-here",
org_scopes=["openid", "internal_org_user_mgt_view"],
)
print(f"Organization token: {org_token.access_token}")
```

### Switch Agent Token to Organization

```python
async def switch_token_flow():
async with AgentAuthManager(config, agent_config) as auth_manager:
# Switch any existing root access token into a child organization context.
org_token = await auth_manager.switch_token_to_organization(
token="existing_access_token",
switching_organization="org-uuid-here",
scopes=["openid", "internal_org_user_mgt_view"],
)
print(f"Organization token: {org_token.access_token}")
```

## API Reference
Expand All @@ -85,11 +142,39 @@ async def user_auth_flow():

Main class for handling agent authentication and OBO flows.

#### Constructor

```python
AgentAuthManager(
config: AsgardeoConfig,
agent_config: Optional[AgentConfig] = None,
authorization_timeout: int = 300,
)
```

#### Methods

- `get_agent_token(scopes: Optional[List[str]] = None) -> OAuthToken`: Get access token for the agent
- `get_authorization_url(scopes: List[str], state: Optional[str] = None) -> Tuple[str, str]`: Generate authorization URL
- `get_obo_token(auth_code: str, agent_token: str, scopes: Optional[List[str]] = None) -> OAuthToken`: Exchange auth code for user token
| Method | Description | Returns |
|--------|-------------|---------|
| `get_agent_token(scopes)` | Authenticates the agent via native auth (username/password + PKCE) | `OAuthToken` |
| `get_organization_agent_token(switching_organization, agent_scopes, org_scopes)` | Gets agent token then switches it to a child-org in one call | `OAuthToken` |
| `get_authorization_url(scopes, state, resource, **kwargs)` | Builds an OAuth2 authorization URL to redirect a user to | `Tuple[str, str]` — `(url, state)` |
| `get_authorization_url_with_pkce(scopes, state, resource, **kwargs)` | Same as above but generates and returns a PKCE `code_verifier` | `Tuple[str, str, str]` — `(url, state, code_verifier)` |
| `get_org_authorization_url(scopes, org_discovery_type, discovery_value, ...)` | Authorization URL with org-discovery params (`orgID`, `orgHandle`, `org`, `emailDomain`) | `Tuple[str, str]` — `(url, state)` |
| `get_org_authorization_url_with_pkce(scopes, org_discovery_type, discovery_value, ...)` | Org authorization URL with PKCE | `Tuple[str, str, str]` — `(url, state, code_verifier)` |
| `get_obo_token(auth_code, agent_token, scopes, code_verifier)` | Exchanges a user's auth code for an OBO token delegated to the agent | `OAuthToken` |
| `get_obo_token_with_ciba(login_hint, agent_token, scopes, ...)` | Push-based OBO — sends auth request to user's device and polls until approved | `Tuple[CIBAResponse, OAuthToken]` |
| `switch_token_to_organization(token, switching_organization, scopes)` | Switches any access token into a child-org scoped token | `OAuthToken` |
| `revoke_token(token, token_type_hint)` | Revokes an access or refresh token | `bool` |

#### `get_org_authorization_url` / `get_org_authorization_url_with_pkce` — `org_discovery_type` values

| Value | `discovery_value` meaning |
|-------|--------------------------|
| `"orgID"` | Organization UUID |
| `"orgHandle"` | Organization handle/slug |
| `"org"` | Organization name |
| `"emailDomain"` | User email address (used as `login_hint` with domain-based discovery) |

### AgentConfig

Expand Down
Loading
Loading