Skip to Content
Platform

AAuth

Your agent acts at another company’s API for a person. AAuth lets that person’s organisation approve it, once per mission, with a budget.

AAuth support is experimental: the API, SDK and CLI shapes may change between minor releases.

AAuth  is an open protocol for agents acting on someone’s behalf. The agent signs every request; the AAuth resource it calls asks the person’s Person Server for an authorization decision; and the Person Server answers with a token the AAuth resource trusts. Introspection supports the native flow AAuth calls Person Server Managed: the AAuth resource issues a resource token bound to the person, and the Person Server returns an auth token for it.

Your recipe holds no credential for any of this. Introspection is the agent’s Agent Provider, and the platform’s egress signs each request for the session.

PartyWho runs it
AgentYour recipe, in its sandbox
Agent ProviderIntrospection: it issues the agent’s token, bound to a key per session
AAuth resourceThe API your agent calls, such as a booking provider. Build one with @introspection-sdk/aauth-resource or the Rust aauth-protocol crate
Person ServerThe person’s organisation: its own, or the one Introspection hosts

Missions and approvals

A mission is one approval for a piece of work, such as “Flights and a hotel for Sam, Monday to Friday next week, up to $3,000.” In the travel example below, Sam asks the agent and Dana, Sam’s manager at Acme, approves:

  1. The agent proposes the mission. The person’s approver approves it once and can set its budget.
  2. Requests within the mission’s budget go through at once and are spent against it. One over what is left goes back to the approver.
  3. When the work is done, the agent asks the person to accept the mission as complete. A completed mission issues nothing more.

While a request waits for someone, the agent’s call answers with HTTP status 428 Precondition Required: the request is valid, but it needs a person’s approval first. The response says what is waiting, and the agent tells the person instead of retrying.

When the approver decides, Introspection resumes the conversation with the outcome: approved, declined, or lapsed with no decision. A deferred approval stays open for 48 hours unless your plane is configured otherwise.

Connect an AAuth API

You need: an owner or admin, and the API’s AAuth resource identifier.

  1. Create the application your agent acts as. Its client id is the agent’s identity at the Person Server:
    introspection applications create --type service-account --name "Travel agent"
  2. Create the connector. --api-host is the host your recipe calls, and the egress signs every request to it:
    introspection connectors create --name "Booking" --provider booking --auth-mode aauth \ --api-host api.booking.example \ --person-server-url https://ps.acme.example \ --application-id <application-id> \ --metadata aauth_resource=https://api.booking.example
  3. In your recipe, call the API with plain fetch. To propose a mission, post {description} to https://person-server.aauth/mission: the egress fills in who the agent acts for and which resources it covers, signs it, and sends it to the connector’s Person Server.

A recipe that routes connectors in policies/routes.yaml gets only the AAuth connectors it routes. Its policy rails still run before any request is signed.

Choose a Person Server

  • The customer’s own. Point --person-server-url at it. The customer keeps approvals and missions; Introspection only signs and polls. Build one with @introspection-sdk/person-server or the Rust aauth-person-server crate.
  • The one Introspection hosts. A data plane can host a Person Server, with each project as its own tenant. Point --person-server-url at the plane’s Person Server, add --metadata aauth_tenant=<org-id>:<project-id>, and decide approvals from your own app as below. Ask us to turn it on for your plane.

Decide approvals from your app

On the hosted Person Server, your app owns the human side: it finds what is waiting, reaches the approver however it likes, and records the answer. Use an application with approvals:read approvals:write; agent sessions never hold these scopes, so an agent cannot approve its own mission.

  1. List what is waiting:
    introspection aauth approvals list --status pending
    Each approval names the person it is for (member_id), its description, and the AAuth resource’s own summary of the request.
  2. Record the decision, naming who decided. A mission approval can set its budget, in minor units:
    introspection aauth approvals decide <approval-id> --approve \ --decided-by user:dana@acme.example --budget-amount 300000 --budget-unit USD
    Name the approver with --decided-by user:<id>, anon:<id> or member:<uuid>; it is recorded as their member id. A completion is the person’s own to accept.
  3. See approved missions and what each has spent: introspection aauth missions list.

From Rust, the same calls are on client.aauth():

let decision = ApprovalDecision::approve(DecidedBy::user("dana@acme.example")) .with_budget(Budget { amount: 300_000, unit: "USD".into(), decimals: 2 }); client.aauth().approvals().decide(approval_id, &decision).await?;

The endpoints are in the API reference. The mission text and approval descriptions are encrypted at rest.

Example

The AAuth travel demo  books flights and a hotel for Sam, an Acme employee. Dana, Sam’s manager at Acme, approves the trip as a mission with a budget; Flight Sector’s booking API is the AAuth resource. It runs against Acme’s own Person Server or the hosted one, and pnpm dev sets up the connector, the applications and the recipe for you.

Last updated on