Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.alterauth.com/llms.txt

Use this file to discover all available pages before exploring further.

Get started with the Alter SDK for Python to make authenticated API calls to any OAuth provider, manage connections, and initiate OAuth flows. The SDK supports OAuth tokens, API keys, and custom credentials, all retrieved and injected automatically.

Installation

Requires Python 3.11 or higher.
pip install alter-sdk
For framework integrations:
pip install 'alter-sdk[fastapi]'    # FastAPI integration
pip install 'alter-sdk[mcp]'        # FastMCP integration
pip install 'alter-sdk[langchain]'  # LangChain integration
For native boto3 integration with AWS services:
pip install 'alter-sdk[aws]'

Basic Setup

The fastest way to get started: connect() opens a browser, the user authorizes, and the SDK returns a grant to use immediately:
import asyncio
from alter_sdk import AlterVault, HttpMethod

async def main():
    vault = AlterVault(
        api_key="alter_key_...",
        caller="my-agent",
    )

    # Open browser → user authorizes → SDK returns connection
    results = await vault.connect(
        providers=["google"],
    )
    print(f"Connected: {results[0].grant_id}")

    # Make API calls with the grant
    response = await vault.request(
        HttpMethod.GET,
        "https://www.googleapis.com/calendar/v3/calendars/primary/events",
        grant_id=results[0].grant_id,
        query_params={"maxResults": "10"},
    )
    events = response.json()

    for event in events.get("items", []):
        print(f"Event: {event['summary']}")

    await vault.close()

asyncio.run(main())
Key Principle: Zero Token Exposure - You never see or handle OAuth tokens. The SDK retrieves them from Alter Vault and injects them automatically. All SDK-to-backend communication is cryptographically secured for integrity, authenticity, and replay protection.
Already have a grant_id? Skip connect() and go straight to vault.request(method, url, grant_id=grant_id). The connect() method is for when a new OAuth flow needs to be initiated from code. For web apps with a frontend, use Alter Connect instead.

Configuration

from alter_sdk import AlterVault, CallerType

vault = AlterVault(
    api_key="alter_key_...",              # Required: API key from dashboard
    caller="my-agent",                    # Optional: Caller identity for audit logs
    caller_type=CallerType.AGENT,         # Optional: AGENT (default) or SERVICE
    timeout=30.0,                         # Optional: HTTP timeout in seconds
)
Use CallerType.SERVICE for backend infrastructure callers that should not appear in the Developer Portal Agents tab. Audit logging is always enabled — every token retrieval and API call is automatically logged for compliance and security. The SDK automatically includes the HTTP method and target URL in the audit trail for each token request.

Connecting an Identity Provider

If the application uses an external IDP (Okta, Entra ID, Auth0, Clerk, Keycloak, or any OIDC issuer), wire it up to the SDK so every request is scoped to the signed-in end user. This is required for provider= lookups (identity-based grant resolution) and powers group-based policies and instant deprovisioning. One-time setup (Developer Portal): configure the app’s IDP on the Identity page — paste the OIDC issuer URL, click Discover, then save. Alter Vault auto-detects the IDP type and claim mappings. Each app can have only one IDP at a time; switching providers requires removing the current IDP configuration and then adding the replacement. See the IDP Setup Guide for per-provider steps. Per-request wiring (SDK): pass a user_token_getter that returns the end user’s IDP-issued JWT. The SDK attaches it to every token request so the backend can resolve the user from the JWT claims.
from alter_sdk import AlterVault, HttpMethod

vault = AlterVault(
    api_key="alter_key_...",
    caller="my-agent",
    # Called before every request — return a fresh JWT for the current user.
    # Sync or async callables are both supported.
    user_token_getter=lambda: get_current_user_jwt(),
)

# `provider=` looks up the grant that belongs to the JWT's user — no grant_id needed.
response = await vault.request(
    HttpMethod.GET,
    "https://www.googleapis.com/calendar/v3/calendars/primary/events",
    provider="google",
)
Two resolution modes — pass grant_id= when the caller already knows the exact grant, or pass provider= with an active end-user token source so the backend can resolve the grant from the JWT’s sub claim. The token source can come from constructor user_token_getter or from a token cached via vault.authenticate().
End-user login flow (optional): if the application does not already have a JWT for the user, call vault.authenticate() to open a browser-based OIDC login through the IDP and receive the user profile. The SDK caches the resulting token internally and installs it as the active token source for that AlterVault instance. If constructor user_token_getter was set earlier, vault.authenticate() overrides it for subsequent provider= requests. Configure the IDP’s wallet/SDK client credentials in the Developer Portal first.
auth_result = await vault.authenticate()
print(auth_result.user_info)  # { sub, email, name, ... } from the IDP

Connecting Without an IDP

The SDK does not require an identity provider. When AlterVault is constructed without a user_token_getter, every Connect session it produces creates a system-principal grant — bound to the app, not to any end user, and addressed by grant_id. This is the path for server-to-server jobs, CLI tools, fixture provisioning, and any environment where there is no signed-in user.
from alter_sdk import AlterVault, HttpMethod

vault = AlterVault(api_key="alter_key_...")  # no user_token_getter

# Start the OAuth flow. With no user_token, the resulting grant is system-principal.
session = await vault.create_connect_session(allowed_providers=["google"])
print("Open this URL to authorize:", session.connect_url)

# After the operator completes OAuth in the browser, look up the new grant.
# Because no user_token_getter is configured, list_grants() returns app-scoped grants.
result = await vault.list_grants(provider_id="google", limit=5)
grant = result.grants[0]
assert grant.principal_type == "system"

response = await vault.request(
    HttpMethod.GET,
    "https://www.googleapis.com/calendar/v3/calendars/primary/events",
    grant_id=grant.grant_id,
)
System-principal grants do not appear in any end user’s Wallet Dashboard. Revoke them from the Developer Portal or via SDK with the grant_id. A runnable example covering custom managed secrets, AWS, Cloudflare, and non-IDP OAuth lives at examples/system-principal-sandbox/.

Quick Error Handling

from alter_sdk.exceptions import (
    ReAuthRequiredError,
    ScopeReauthRequiredError,
    PolicyViolationError,
    TokenRefreshInProgressError,
    GrantNotFoundError,
    AmbiguousGrantError,
)

try:
    # Identity mode — the SDK resolves the grant from the configured
    # user_token_getter. AmbiguousGrantError can only be raised on this
    # path; direct (grant_id=...) mode addresses a single grant.
    response = await vault.request(
        HttpMethod.GET,
        "https://www.googleapis.com/calendar/v3/calendars/primary/events",
        provider="google",
    )
except ScopeReauthRequiredError as e:
    print(f"Scopes changed — user must re-authorize (provider: {e.provider_id}, grant: {e.grant_id})")
except ReAuthRequiredError:
    print("User must re-authorize via Alter Connect")
except PolicyViolationError as e:
    print(f"Access denied by policy: {e.message} (rule: {e.policy_error})")
except TokenRefreshInProgressError as e:
    # Another request is mid-refresh — transient, retry after backoff
    print(f"Token refresh in progress for {e.grant_id} — retry after backoff")
except AmbiguousGrantError as e:
    # JWT identity resolution matched multiple active grants — supply
    # `account` to disambiguate. The matching identifiers are exposed on
    # the exception so the caller can prompt or pick.
    print(f"Multiple grants for {e.provider_id}: {e.account_identifiers}")
except GrantNotFoundError:
    print("User hasn't connected Google yet")

Revoking a Grant

Permanently revoke a grant when it’s no longer needed. Tokens are deleted from Vault and the grant status is set to revoked. The user must re-authorize via Alter Connect to restore access.
result = await vault.revoke_grant(
    grant_id=grant_id,
    reason="Agent cleanup: stale grant",  # optional; stored in the audit log
)
print(f"Revoked at {result.revoked_at}")
revoke_grant() raises GrantNotFoundError if the grant does not exist or is already revoked. When the AlterVault instance has user_token_getter configured (including the AlterFastAPI dependency), revoke_grant() targets a grant owned by the authenticated caller — passing a grant_id that belongs to someone else raises GrantNotFoundError. See Scoping grant operations to the authenticated user in the overview.

Provisioning Managed-Secret Grants

create_managed_secret_grant() ties a managed secret to a specific principal (user, IDP group, or system). Use it when an admin or backend job needs to provision access without sending the end user through Alter Connect.
from alter_sdk import AlterVault, GroupPrincipal, UserPrincipal, SystemPrincipal

# Tie the secret to an IDP group — every member with a verified JWT gets access
grant = await vault.create_managed_secret_grant(
    "a1b2c3d4-5e6f-7890-abcd-ef0123456789",
    principal=GroupPrincipal(
        idp_id="idp_xyz",
        external_group_id="okta-group-engineering",
        label="engineering-prod-stripe",
    ),
)

# Tie the secret to a specific end user (validates user_token against the IDP).
# `label` is required so the wallet can render meaningful copy.
grant = await vault.create_managed_secret_grant(
    "a1b2c3d4-5e6f-7890-abcd-ef0123456789",
    principal=UserPrincipal(
        user_token=current_user_jwt,
        label="alice-prod-stripe-readonly",
    ),
)

# Headless system grant — no end-user identity required. `label` is optional
# because system grants typically don't surface in the wallet.
grant = await vault.create_managed_secret_grant(
    "a1b2c3d4-5e6f-7890-abcd-ef0123456789",
    principal=SystemPrincipal(label="cron-stripe-charges"),
)

print(grant.grant_id, grant.principal_type)
Principal is a discriminated union (type field is the discriminator). label is required on UserPrincipal and GroupPrincipal (rendered in the wallet) and optional on SystemPrincipal. The backend resolves and persists the principal: UserPrincipal validates the JWT and binds the grant to the resolved app user; GroupPrincipal upserts the IDP group; SystemPrincipal records a headless grant — anyone with the grant id and a valid signature for the app can retrieve the credential, so use only for backend flows with no caller user.

Next Steps

SDK Overview

Core concepts, complete examples, caller tracking, and error handling

FastMCP Integration

Build MCP tools with automatic OAuth credential injection

LangChain Integration

Build LangChain/LangGraph tools with automatic audit context

Quickstart Guide

Full integration walkthrough with frontend + backend