Agent Governance
First-class identities for AI agents / MCP clients — ephemeral tokens, a named human sponsor, Shadow-AI discovery, an AuthZEN PDP facade, and a tenant-wide kill-switch.
An agent is a first-class, non-human principal — the identity an AI agent or MCP client authenticates as, distinct from the users and service principals that already exist. Every capability on this page is designed around one rule: an agent is never unaccountable. It's short-lived, scoped, revocable, and always owned by a named human.
Also in the console
The Qeet ID admin console has a dedicated Agent Governance section (Developer → Agent Governance) covering everything below except Token Vault and CIBA, which are API-only today.
Create an agent
/v1/tenants/{tenantID}/agentsCreate an agent{
"name": "support-copilot",
"scopes": ["tickets:read", "kb:read"],
"token_ttl_seconds": 600,
"sponsor_user_id": "…"
}The response includes a secret, shown exactly once — there's no re-read endpoint.
sponsor_user_id is required and must be an actual member of the tenant (see
Sponsor model below).
/v1/tenants/{tenantID}/agentsList agents/v1/tenants/{tenantID}/agents/{id}Suspend / resume an agent/v1/tenants/{tenantID}/agents/{id}Decommission an agentAn agent moves through a small lifecycle — active → suspended (reversible) →
decommissioned (terminal, excluded from listings).
Mint a token
/v1/agents/tokenMint an agent tokenThe agent authenticates with its id + secret and gets a short-lived, scoped access
token marked actor_type="agent". Tokens are ephemeral by design — there's no
refresh token; the agent re-mints when it needs a new one. Lifetime is clamped to
60s–3600s.
Tenant-wide kill-switch
If an agent (or a whole fleet) misbehaves, one call suspends every active agent in the tenant — their tokens stop working immediately on next verification.
/v1/tenants/{tenantID}/agents/kill-allSuspend all agentsAgent-as-Principal
An agent token self-describes as a non-human principal via claims rather than a
separate sub namespace — actor_type="agent" plus agent_id on every issued token
and on /oauth/introspect. (A sub-prefix convention was considered and rejected: it
would break Token Exchange's subject-token parsing for a purely
cosmetic gain.) Discovery advertises the principal types a client can expect to see:
{
"actor_types_supported": ["user", "service", "agent"]
}Sponsor model
Every agent has a named human sponsor — the accountable owner, validated as an actual tenant member at creation time. When a sponsor leaves the organization, their agents don't go orphaned:
/v1/tenants/{tenantID}/agents/sponsored-by/{userID}List a user's sponsored agents/v1/tenants/{tenantID}/agents/sponsored-by/{userID}/transferTransfer sponsorship{ "to_user_id": "…" }Transfer reassigns every agent the departing sponsor owned in one call and returns the count moved. The console's sponsor-transfer tool previews that count before you confirm.
Shadow-AI discovery
Not every piece of automation goes through this registry on purpose — an OAuth client
can pick up client_credentials or token-exchange without anyone registering it as a
managed agent or service principal. Qeet ID flags those as Shadow-AI candidates,
ranked by how many live (unexpired, unrevoked) refresh tokens they're actually holding:
/v1/tenants/{tenantID}/oidc/clients/shadow-aiList Shadow-AI candidates/v1/tenants/{tenantID}/oidc/clients/{id}/reviewAcknowledge a candidateAcknowledging a candidate doesn't change its permissions — it's an attestation that a human has looked at it, recorded with who and when.
AuthZEN — an external PDP facade
For a policy-enforcement point that would rather speak a standard protocol than Qeet
ID's own /check shape — an MCP tool-call gateway, for instance — the
OpenID AuthZEN core evaluation API
fronts the same RBAC/ReBAC engines documented in Authorization:
/v1/tenants/{tenantID}/access/v1/evaluationAuthZEN evaluation{
"subject": { "type": "user", "id": "…" },
"resource": { "type": "permission" },
"action": { "name": "billing:write" }
}{
"subject": { "type": "user", "id": "…" },
"resource": { "type": "document", "id": "readme" },
"action": { "name": "editor" },
"context": { "explain": true }
}resource.type="permission" routes to RBAC (action.name is the permission key,
resource.id is ignored); anything else routes to ReBAC (resource becomes
"type:id", action.name becomes the relation). context.explain: true returns the
same grant-path trace as each engine's own ?explain=true.
Token Vault & CIBA
Two more pieces of the governance surface, API-only today (no console UI yet):
- Token Vault — a per-tenant encrypted store for third-party OAuth tokens
(Slack/GitHub/Google/custom), so an agent holding a delegated token can reach the
delegating user's own connected account without ever seeing the raw refresh token.
POST /v1/tenants/{tenantID}/vault/providers, connect viaGET .../vault/{provider}/connect, thenGET .../vault/tokens/{provider}for an auto-refreshed access token. - CIBA (backchannel authentication) — the async, no-browser sibling of the
Device Authorization Grant: a client resolves the user via
login_hintand polls while an in-app notification collects consent.POST /v1/oauth/bc-authorizeto start,POST /v1/oauth/tokenwithgrant_type=urn:openid:params:grant-type:cibato poll.
Both are governed by the same primitives as everything else on this page — scoped, revocable, and attributable to a human — they just don't have a dedicated admin screen distinct from their API contract yet.