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.

Once a managed secret is stored in the developer portal, the next step is to “issue” a grant on it — a per-principal access path identified by a grant_id. The same secret can be issued as separate grants to different users, groups, agents, or as a system grant. This page covers the SDK surface. The portal’s UI does the same thing — pick whichever fits the workflow.

When to use the SDK vs the portal

PortalSDK
One-off provisioning by an operatorProgrammatic provisioning (onboarding, multi-tenant)
A click-through audit trail is preferredGrants need to spin up per agent / per tenant in code
Binding to many users at onceIssuing from inside a deployment workflow

Issuing a grant

create_managed_secret_grant() is available on both App (operator) and Agent (workload) — but agents can only issue grants for themselves.

Principals

PrincipalRequired fieldsNotes
UserPrincipaluser_token, labelResolves to a single end user via the IDP JWT.
GroupPrincipalexternal_group_id, idp_id, labelResolves to any member of the IDP group.
SystemPrincipalNo caller identity. Server-to-server / cron-style.
AgentPrincipalResolves the calling agent from the API key on the request. Carries no agent_id.
In the TypeScript SDK these are interfaces, not classes — construct them as object literals (no new).
from alter_sdk import UserPrincipal, AgentPrincipal, SystemPrincipal

# Issue a Stripe grant to a specific user
result = await app.create_managed_secret_grant(
    managed_secret_id="ms_abc123",
    principal=UserPrincipal(user_token=alice_jwt, label="alice-prod-stripe"),
)
print(result.grant_id)

# Issue a Stripe grant to an agent. The grant binds to whichever agent's
# API key is on the request — `AgentPrincipal` carries no agent_id field.
billing_bot = app.get_agent("billing-bot")
result = await billing_bot.create_managed_secret_grant(
    managed_secret_id="ms_abc123",
    principal=AgentPrincipal(label="billing-bot-stripe"),
)

# Issue a system-wide grant (no principal binding)
result = await app.create_managed_secret_grant(
    managed_secret_id="ms_abc123",
    principal=SystemPrincipal(label="payouts-cron-stripe"),
)
managed_secret_id is the secret’s identifier from the developer portal. principal decides who owns the resulting grant. label is the human-readable name shown in the wallet and in audit logs.

Setting a grant policy (TTL)

Pass grant_policy= to bound the grant’s lifetime:
result = await app.create_managed_secret_grant(
    managed_secret_id="ms_abc123",
    principal=UserPrincipal(user_token=alice_jwt, label="alice-prod-stripe"),
    grant_policy={"max_ttl_seconds": 30 * 86400},
)
The grant becomes unusable after the TTL elapses. Use this for short-lived access (incident response, contractor onboarding) where revoking later isn’t reliable.

Agent-issued grants

Agents (the Agent class) can issue grants — but only for themselves. The backend resolves the calling agent from the HMAC-verified API key on the request.
# Inside agent code
result = await vault.create_managed_secret_grant(
    managed_secret_id="ms_abc123",
    principal=AgentPrincipal(label="self-issued-stripe"),
)
This pattern enables an agent to self-provision access at startup. The agent must already have permission to use the underlying managed secret.

Listing managed-secret grants

Managed-secret grants appear in list_grants() alongside OAuth grants — they’re returned as ManagedSecretGrantItem objects (vs OAuthGrantItem for OAuth grants). The discriminator field is grant_kind (Python) / grantKind (TypeScript):
page = await vault.list_grants(limit=100)
for item in page.grants:
    if item.grant_kind == "managed_secret":
        print(item.grant_id, item.managed_secret_id, item.managed_secret_slug, item.label)
See OAuth → Managing grants for the full listing API and revocation.

See also