Skip to content

AI Agents — first-class identity, audit, and revocation

Story 23.4 ships the Agents feature surface: AI agents are no longer generic OAuth clients with a clientType='agent' discriminator buried in the OAuth-clients UI — they get their own dashboard navigation entry, their own activity timeline, their own rate-limit + token-TTL ceilings, and a first-class per-user revocation primitive aligned with GDPR Art. 7(3) consent withdrawal.

SurfaceWherePurpose
Dashboard /app/{slug}/agentsTenant ownersRegister, list, observe, revoke agents
/v1/auth/dashboard/tenants/{slug}/agents/**Dashboard APIProgrammatic admin (session auth)
/v1/users/me/agents (GET / DELETE)End usersList + revoke agents acting on my behalf
client.users.me.agents.{list,revoke}Node SDKEnd-user revocation from your apps
agent.* audit + webhook eventsTenant subscribersOperational + compliance evidence

When to register an agent vs. a regular OAuth client

Section titled “When to register an agent vs. a regular OAuth client”

Register an agent when:

  • The client acts on behalf of a specific user (the act claim identifies the agent; sub identifies the human).
  • You want per-user revocation to satisfy GDPR Art. 7(3) consent withdrawal without rotating the agent’s secret.
  • The fleet of clients needs uniform rate limits, alerts, and an audit trail that survives admin handovers.

Register a regular OAuth client when:

  • The client is a first-party app signing in human users via authorization code (no act claim, no agent semantics).
  • You only need machine-to-machine access (client_credentials) without any user delegation.

Agents typically combine some of these grant types — the agent registration allowlists them all:

  1. RFC 8693 Token Exchange (Story 23.2) — the agent already holds a user’s access token and exchanges it for a scoped-down agent token. Inline and synchronous; no user prompt at exchange time.
  2. OIDC CIBA (Story 23.3) — the agent initiates a request; the user approves out-of-band on a separate device; the agent polls until issuance.
  3. RFC 8628 Device Authorization (Story 23.1) — CLI / IoT-style agents print a code and URL; the user signs in on a browser.

Every issued token carries an act claim identifying the agent client. The Node SDK’s verifyToken() exposes this as payload.act and Auth.isAgentToken(token) returns true for any agent-issued token.

From the dashboard: Agents → Register agent. Enter:

  • Name — human-readable label.
  • Description (optional) — what the agent does.
  • Class (optional) — free-form label (e.g. mcp-server, voice, llm); surfaced in audit views.
  • Allowed scopes — space-separated list. Tokens issued for this agent are intersected against this allowlist.
  • Grant types — check at least one of: token-exchange, CIBA, device-code, client-credentials.
  • Max token TTL (seconds) — 60–900s ceiling. Lower = smaller blast radius if a token leaks. Default 300s.

The dashboard reveals the client_secret exactly once at the end of the wizard — copy it to your secret store immediately.

Tenant admin revoke (DELETE /v1/auth/dashboard/tenants/{slug}/agents/{agentId}):

  • Sets revoked_at on the agent row.
  • Inserts an agent_token_denylist row valid for the agent’s max TTL.
  • Bearer-auth middleware rejects every subsequent token whose act.sub matches the agent (immediate, not eventual).
  • Idempotent — re-revoking returns 200 with the existing revoked_at.

End-user revoke (DELETE /v1/users/me/agents/{agentClientId}, GDPR Art. 7(3)):

  • Inserts a user_agent_revocations row keyed (tenant_id, user_id, agent_client_id).
  • Token-issuance gates in token-exchange + CIBA reject any future mint where (act.sub, sub) matches a revocation row.
  • Already-issued tokens remain valid until their TTL expires (≤900s ceiling bounds the residual window). Tenants requiring instant per-token invalidation use the admin revoke path above.
  • Idempotent — re-revoking returns 200 with the existing row, no duplicate audit / webhook events.

Every agent action is recorded in agent_actions with: action type, actor user, resource, JTI, scope, IP / user-agent SHA-256 prefixes (12 chars surfaced; raw hashes never leave the server). The dashboard renders a paginated timeline at Agents → {agent} → Activity; the API exposes it via GET /v1/auth/dashboard/tenants/{slug}/agents/{agentId}/activity.

Retention: 180 days (operational feed). Critical events (issuance, revocation, blocked-on-revocation) are dual-written to audit_log (immutable archive, 3-year retention) for compliance.

Eight audit event types fire on the agent lifecycle:

EventWhenSeverity
agent.createdNew agent registeredlow
agent.updatedSettings / scopes / grants changedlow
agent.secret_rotatedSecret rotationmedium
agent.revokedTenant admin revokehigh
agent.user_revokedEnd-user revokemedium
agent.rate_limitedRate limit hitmedium
agent.concurrent_token_limit_reachedmax_concurrent_tokens cap hitmedium
agent.token_blocked_user_revokedToken mint blocked by per-user gatehigh

Four webhook event types are emitted to tenant subscribers: agent.created, agent.revoked, agent.user_revoked, agent.alert_triggered. Subscribe via the existing /v1/auth/dashboard/tenants/{slug}/webhooks family.

Agents are a Pro+ feature. Free-tier tenants see a tier-locked CTA and cannot register agents. Pricing details: see your billing dashboard.