Agent Auth (OAuth 2.1)
OAuth 2.1 identity service for autonomous agents. Supports client credentials flow, token introspection (RFC 7662), revocation (RFC 7009), and delegated token exchange for agent-to-agent authentication.
Base path: /api/v1/cloud/auth
POST /clients
Create an OAuth 2.1 client for a registered agent. The client_secret is returned only once.
agent_registration_id accepts the agent_id returned by
POST /cloud/agents/register (e.g.
agent-a1b2c3d4e5f6) — it's resolved to the registration's internal id automatically, so the
only identifier the Registry ever gives you just works here (Refs #9301).
curl -X POST https://api.ainative.studio/api/v1/cloud/auth/clients \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"agent_registration_id": "agent-a1b2c3d4e5f6",
"scopes": ["agent.register", "memory.recall", "memory.store"],
"token_ttl_seconds": 3600
}'
Response (201):
{
"id": "client-uuid",
"client_id": "agt_abc123def456",
"client_secret": "sk_agent_xxxxxxxxxxxx",
"scopes": ["agent.register", "memory.recall", "memory.store"],
"token_ttl_seconds": 3600
}
POST /token
Client credentials grant. Exchange client_id + client_secret for an access token.
grant_type must be client_credentials — this is the only grant type implemented for
agent OAuth. Any other value (e.g. authorization_code) returns 400 Bad Request with
"Unsupported grant_type: ... Only 'client_credentials' is supported.".
curl -X POST https://api.ainative.studio/api/v1/cloud/auth/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials&client_id=agt_abc123&client_secret=sk_agent_xxx&scope=agent.register memory.recall"
Response:
{
"access_token": "eyJ...",
"token_type": "Bearer",
"expires_in": 3600,
"scope": "agent.register memory.recall"
}
POST /token/introspect
Validate a token per RFC 7662. Use this to verify tokens from other agents.
curl -X POST https://api.ainative.studio/api/v1/cloud/auth/token/introspect \
-H "Content-Type: application/json" \
-d '{"token": "eyJ..."}'
Response:
{
"active": true,
"client_id": "agt_abc123def456",
"scope": "agent.register memory.recall",
"exp": 1712200000,
"iat": 1712196400
}
POST /token/revoke
Revoke a token per RFC 7009.
curl -X POST https://api.ainative.studio/api/v1/cloud/auth/token/revoke \
-H "Content-Type: application/json" \
-d '{"token": "eyJ..."}'
POST /token/delegate
Delegated token exchange for agent-to-agent auth. Agent A can request a scoped token to act on behalf of a user when calling Agent B.
curl -X POST https://api.ainative.studio/api/v1/cloud/auth/token/delegate \
-H "Authorization: Bearer $AGENT_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"parent_token": "eyJ...",
"target_agent_id": "agent-target-xyz",
"scopes": ["memory.recall"]
}'
parent_token is the calling agent's own access token — the delegated token's scopes must be a
subset of the parent's. There is no ttl_seconds field; the delegated token's lifetime is fixed
server-side.
Response:
{
"access_token": "eyJ...",
"token_type": "bearer",
"expires_in": 600,
"scope": "memory.recall"
}
Available Scopes
The canonical scope taxonomy lives in AgentOAuthService.VALID_SCOPES — passing any scope
outside this list returns a real 400 Invalid scopes.
| Scope | Description |
|---|---|
agent.register | Register a new agent |
agent.delegate | Request a delegated token to act on behalf of another agent |
memory.recall | Recall memories, search vectors |
memory.store | Store memories, add vectors |
memory.forget | Delete memories |
zerodb.read | Read ZeroDB tables/vectors |
zerodb.write | Write ZeroDB tables/vectors |
zerodb.admin | Administer ZeroDB projects |
chat.complete | Chat completions |
chat.stream | Streaming chat completions |
stream.ingest | Ingest into a live stream |
stream.read | Read from a live stream |
file.upload | Upload files |
file.download | Download files |
mcp.connect | Connect to an MCP server |
mcp.execute | Execute MCP tool calls |