Skip to content
Agent Identity

Deployment · runtime shape

How the agent is deployed, and which protocols apply

Sequence diagrams live under Flows. This page is the other cut: the runtime topology — product UI, headless worker, MCP host, mesh sidecar, true p2p HTTP — and the specs that actually attach to that shape. 13 patterns, researched 15 September 2026. Drafts are marked; RFC numbers are not invented. If you are not sure which row you are on, the picker names the shape — it does not score you.

What is your shape · 1 question

Is a human in the loop for this call?

Not 'does the product have users.' Is a person authenticating or approving this hop. This is an explainer, not a score — it names the deployment row you are already in. AAuth p2p, A2A, and did:peer stay on separate exits.

In one board · four doors

Delegated · AAuth p2p · A2A · did:peer

AS in path?
Yes — an authorization server mints the access token
What token?
Bearer or DPoP pass; sub is the user; agent is client_id or act
access token
UserAgent (client)ASAPI

Wrong cousin: Not AAuth identity-based: there is very much an AS. Putting this pass on an A2A call without aud and actor binding is a confused deputy.

Open this door →

There is no IETF RFC titled P2P in this cluster. The word is meeting shorthand. Pick one door and stay in it.

Overview matrix

Rows are deployment patterns. Columns are the questions that decide the protocol: is a user in the loop, is an authorization server minting the credential, does a workload identity name the binary, and does the agent have an identity that is not an AS-local client_id. Each row is a tiny topology of actors. Primary protocol names link into the catalog.

Interactive delegated

User (browser)Agent (OAuth client)Authorization serverAPI / tool

Interactive user-delegated agent

/patterns/interactive-user-delegated

A human is in a product UI. The agent calls APIs as that user. This is still the production default: OAuth 2.1 authorization code + PKCE, OIDC for the user, audience-restricted access tokens.

When you see it

Chat UIs that connect Gmail or Jira, Copilot-in-the-IDE with a browser login, any SaaS 'enable the assistant' button that pops an authorization screen. The agent is an OAuth client; the human is the resource owner.

Actors and trust

  • User / resource ownerUser

    Authenticates to the authorization server (OIDC). Consents to what this client may do.

  • Agent (OAuth client)Agent instance

    Identified by client_id at this AS (or a CIMD URL). Not a portable agent identity. Public or confidential depending on the host.

  • Authorization serverOther

    Issues the access token the API will accept. Often the company IdP or the API vendor's AS.

  • Resource server / APIResource

    Trusts tokens from that AS, audience-restricted to itself (RFC 8707 / RFC 9068). Does not automatically learn which agent instance called.

Topology

User (browser)Agent (OAuth client)Authorization serverAPI / tool
  • User (browser)Asks the product to call an APIAgent (OAuth client)
  • Agent (OAuth client)Auth code + PKCE (PAR if the request is rich)Authorization server
  • User (browser)Authenticates (OIDC) and consentsAuthorization server
  • Authorization serverAccess token (and optional refresh)Agent (OAuth client)
  • Agent (OAuth client)Authorization: Bearer or DPoP; aud = this APIAPI / tool
Human in the browser, agent as OAuth client, AS mints an audience-restricted token, API consumes it.

Primary

Optional

Do not use

  • AAuthdraft / churn

    Not for this hop unless you are replacing the AS. AAuth p2p has no auth-code redirect.

  • Resource Owner Password Credentials

    Removed from OAuth 2.1; forbidden by RFC 9700.

  • Bearer tokens

    Bearer tokens exist, but unconstrained Bearer as the whole design is the 2012 default RFC 9700 is walking away from.

Why these, and not those

You have a browser and a human. Authorization code + PKCE is the OAuth 2.1 default; OIDC authenticates the user to the client; RFC 9728 tells the client which AS protects the API; RFC 8707 keeps the token from being replayed at a different API; RFC 9700 is the safety floor (no implicit, no password grant, exact redirects). PAR and RAR are for fat or fine-grained requests, not a different grant. DPoP or mTLS so a stolen access token is not enough. AAuth identity-based p2p is the wrong tool unless you are deliberately replacing the AS — it has no authorization-code redirect and no Bearer access token.

Related flows

Sequence diagrams, not this topology cut. All flows

Comparisons

Headless / async

Headless agentOpenID provider / person serverUser (other device)API / tool

Headless / async user-delegated

/patterns/headless-async-delegated

The agent runs without a browser on its own device. A human still has to approve, but on another device. CIBA is the OpenID answer; RFC 9470 steps up an existing grant; AAuth interaction relay is the person-server-shaped alternative.

When you see it

A nightly research agent that must confirm before sending mail, a factory-floor bot whose operator has a phone, a CLI agent started over SSH, any 'approve this tool on your phone' prompt. If there is no human at all, that is unattended batch — a different row.

Actors and trust

  • Agent (no browser)Agent instance

    Confidential client at the OpenID provider, or an AAuth agent with a person server.

  • User on another deviceUser

    Approves a binding message (CIBA) or completes an interaction URL (AAuth PS / RFC 9470).

  • OpenID provider or person serverOther

    Authenticates the person and mints the grant the agent will present.

  • Resource serverResource

    Still enforces audience and policy. CIBA is not a replacement for RS checks.

Topology

Headless agentOpenID provider / person serverUser (other device)API / tool
  • Headless agentCIBA backchannel authorize, or AAuth 401 + interactionOpenID provider / person server
  • OpenID provider / person serverPush / binding message / interaction URLUser (other device)
  • User (other device)Approve or denyOpenID provider / person server
  • OpenID provider / person serverAccess token or aa-auth+jwtHeadless agent
  • Headless agentCall with the freshly approved grantAPI / tool
Agent has no browser. The human approves on another device; the grant comes back on the back channel (CIBA) or via the person server (AAuth).

Primary

Optional

Do not use

  • OAuth 2.1

    Authorization-code redirect is the wrong grant when the agent has no browser. Use CIBA (or AAuth interaction), not a fake redirect.

  • Headless browser against the authorize endpoint

    That is not a grant. It is scraping a login page.

  • Resource Owner Password Credentials

    Never collect the user's password in the agent.

Why these, and not those

Authorization code needs a redirect user-agent the agent does not have. CIBA starts the grant on the back channel and pushes the human on an authentication device. RFC 9470 is for the case you already have a grant that is too weak or too stale for this tool. AAuth's person-server interaction relay is the same human-in-the-loop idea without an OAuth AS in the agent–resource hop: the PS parks the request, the person approves, the agent retries with an auth token. Do not automate a headless browser against an authorize endpoint, and do not stuff a user password into the agent.

Related flows

Sequence diagrams, not this topology cut. All flows

Enterprise IdP

EmployeeCompany IdPCompany agentSaaS ASSaaS API

Enterprise SaaS / IdP-brokered

/patterns/enterprise-idp-brokered

A company agent needs Slack, Google, or another SaaS the IdP already federates. The IdP brokers the grant (XAA / ID-JAG) instead of sending the human through a second OAuth circus at every app.

When you see it

Enterprise Copilot or a custom agent that files a ticket in ServiceNow and posts to Slack under the employee's identity, with admin policy deciding which apps are pre-approved. The user signed into the company IdP this morning; the agent should not pop a new consent screen per SaaS if policy already allows the connection.

Actors and trust

  • Employee (user)User

    Has an SSO session at the company IdP. May never see a second consent if policy pre-approves the app connection.

  • Company agent / appAgent instance

    Already registered at the IdP. Not a portable AAuth identity; it is an enterprise OAuth client.

  • Company IdPOther

    Issues an identity-assertion JWT authorization grant (ID-JAG) for the target app's AS.

  • SaaS authorization server + APIResource

    Already trusts this IdP for SSO. Redeems the JWT grant (RFC 7523) for an access token to its own API.

Topology

EmployeeCompany IdPCompany agentSaaS ASSaaS API
  • EmployeeSSO session (OIDC)Company IdP
  • Company agentRequest ID-JAG / identity-chaining grant; aud = SaaS ASCompany IdP
  • Company IdPJWT authorization grantCompany agent
  • Company agentRFC 7523 JWT bearer grantSaaS AS
  • SaaS ASAccess token for this SaaSCompany agent
  • Company agentCall Slack / Google / …SaaS API
IdP already has the user session. It mints a JWT grant for the SaaS AS; the agent never collects a second password.

Primary

Optional

Do not use

  • AAuthdraft / churn

    Enterprise SaaS APIs expect OAuth tokens from an AS they already trust, not Signature-Key.

  • Per-SaaS password or a user refresh token harvested at install time

    The IdP is supposed to broker this. Storing a Google refresh token in the agent bypasses enterprise policy.

Why these, and not those

XAA / ID-JAG is the IdP-brokered profile of 'the user is already signed in here; mint a grant the other app's AS will accept.' Identity chaining is the general two-AS version of the same idea. OIDC is how the IdP authenticated the employee. FAPI 2.0 if the SaaS is high-risk (open banking, payments). This is not AAuth p2p (there is very much an AS in the path) and not MCP (the wire to Slack is Slack's API, not an MCP session). AIMS tells you to compose these RFCs rather than invent a company-specific token.

Related flows

Sequence diagrams, not this topology cut. All flows

MCP host ↔ server

UserMCP hostAuthorization serverMCP server (tools)

MCP host ↔ MCP server (tools)

/patterns/mcp-host-server

A model host (Claude Desktop, an IDE, a custom runtime) calls tools on an HTTP MCP server. The host is the OAuth client. The MCP authorization spec is an OAuth 2.1 profile, not a new token type.

When you see it

Claude Desktop attached to a remote MCP server, Cursor or another IDE with MCP tools, any custom host that speaks MCP HTTP. Stdio MCP is a local pipe and MUST NOT use this OAuth profile — if your 'MCP server' is a subprocess, you are not on this row.

Actors and trust

  • UserUser

    Sits at the host. Authorizes the host to call this MCP server as them.

  • MCP host (client)Agent instance

    The OAuth client. Identified by CIMD URL or (deprecated) DCR. The model never sees OAuth.

  • MCP server (resource)Resource

    The RS. Publishes RFC 9728 metadata, validates audience == itself, does not forward tokens.

  • Authorization serverOther

    Discovered from PRM. Issues tokens audience-restricted to the MCP server URI.

Topology

UserMCP hostAuthorization serverMCP server (tools)
  • MCP hostUnauthenticated MCP HTTP requestMCP server (tools)
  • MCP server (tools)401 + WWW-Authenticate resource_metadata (RFC 9728)MCP host
  • MCP hostCIMD or DCR, auth code + PKCE, resource = MCP URIAuthorization server
  • UserConsent at the host's browserAuthorization server
  • MCP hostAuthorization: Bearer; server checks aud == itselfMCP server (tools)
Host is the OAuth client. MCP server is the resource. The model only sees 'call this tool'.

Primary

Optional

Do not use

  • AAuthdraft / churn

    Only if you deliberately replace MCP-OAuth with agent-native signatures. Default MCP hosts will not.

  • OAuth on stdio MCP

    The MCP spec: stdio MUST NOT use the HTTP authorization profile.

  • Forwarding the host token to another server

    Confused deputy. The MCP server is the audience, not a gateway.

Why these, and not those

MCP HTTP authorization is explicitly an OAuth 2.1 profile: Protected Resource Metadata to find the AS, CIMD preferred over Dynamic Client Registration, authorization code + PKCE, resource indicator = the MCP server. That is why this row is not 'invent a tool token.' AAuth applies only if you deliberately leave the MCP-OAuth profile and speak agent-native HTTP signatures instead — a different contract than the MCP spec, and one MCP hosts will not implement by default. Do not put OAuth on stdio MCP. Do not let the server forward the host's token to someone else.

Related flows

Sequence diagrams, not this topology cut. All flows

Agent as resource

Calling agentAgent Card / RFC 9728Optional ASYour agent (RS)

Agent as HTTP resource / tool provider

/patterns/agent-as-resource

Others call your agent. You are the resource server: publish how to authorize, then enforce it on every request. RFC 9728, an OAuth-protected resource, A2A Agent Card security schemes, or AAuth resource-managed if you run consent yourself.

When you see it

You shipped an HTTP API that is 'the agent.' You host an MCP server. You publish an A2A Agent Card so other agents can assign you tasks. Callers are other products, other agents, or a mesh sidecar — you do not get to assume a browser on their side.

Actors and trust

  • Calling agent / clientAgent instance

    Must obtain whatever your metadata advertised. May be an OAuth client, an AAuth signer, or a mesh workload.

  • Your agent (resource)Resource

    Publishes PRM and/or an Agent Card. Verifies the advertised scheme on the request. Signed Agent Cards prove the card was not tampered with; they do not authenticate the request.

  • Optional authorization serverOther

    Present if you are an OAuth-protected resource. Absent if you are AAuth resource-managed and issue your own session.

Topology

Calling agentAgent Card / RFC 9728Optional ASYour agent (RS)
  • Calling agentGET well-known metadataAgent Card / RFC 9728
  • Calling agentIf the card/PRM says OAuth, obtain a tokenOptional AS
  • Calling agentAuthenticated task or API requestYour agent (RS)
Callers discover your advertised scheme (PRM or Agent Card), obtain credentials, then call you. You are the RS.

Primary

Optional

Do not use

  • Bearer tokens

    API keys / unconstrained Bearer as the only scheme. Last resort, not a design.

  • Signed Agent Card as request authentication

    Card JWS is tamper evidence for the card. Still require a request-level scheme.

Why these, and not those

The caller needs a machine-readable answer to 'how do I authenticate to you?' RFC 9728 is that answer in OAuth. A2A puts the same idea on the Agent Card as securitySchemes (OAuth, OIDC, mTLS, API key). If you do not want an AS, AAuth two-party / resource-managed lets you run your own interaction and issue an opaque session bound to the caller's key. Do not treat a signed Agent Card as request authentication. Do not make API keys the primary scheme if you can avoid it.

Related flows

Sequence diagrams, not this topology cut. All flows

A2A tasking

Client agentAgent CardOptional ASServer agent

Agent-to-agent tasking (A2A)

/patterns/a2a-tasking

Two agents, Agent Cards, a task protocol. A2A v1.0 is how they talk. Authentication is whatever the card advertised — usually OAuth at those endpoints. This is not AAuth identity-based p2p, and it is not did:peer / DIDComm.

When you see it

A planner agent delegates a 'book travel' skill to a specialist that published /.well-known/agent-card.json. Enterprise agent fabrics that speak JSON-RPC/gRPC/HTTP+JSON with A2A-Version. Google-originated protocol, now under AAIF / Linux Foundation.

Actors and trust

  • Client agentAgent instance

    Reads the server's Agent Card, obtains credentials out of band, then calls a supported interface.

  • Server agentResource

    Advertises skills, interfaces, and securitySchemes. Enforces the scheme on each operation.

  • Optional enterprise ASOther

    Present when the card says OAuth or OIDC. Absent when the card says mTLS or an API key.

Topology

Client agentAgent CardOptional ASServer agent
  • Server agentPublishes /.well-known/agent-card.jsonAgent Card
  • Client agentFetch; optionally verify JWSAgent Card
  • Client agentIf the card says OAuth/OIDC, obtain a token out of bandOptional AS
  • Client agentAuthenticated A2A operation (JSON-RPC / gRPC / HTTP+JSON)Server agent
Discovery is the Agent Card. The task hop then uses whatever securitySchemes the card listed — usually OAuth, not AAuth signatures.

Primary

Optional

Do not use

  • AAuthdraft / churn

    AAuth p2p is signed HTTP with an agent token. A2A does not use Signature-Key. Keep the rows distinct.

  • did:peer

    Pairwise DID, not a globally fetched Agent Card.

  • DIDComm

    A different messaging stack. Not A2A tasks.

  • In-band credential exchange down the chain

    A2A §7.6.3: secrets become visible to every hop. Prefer out-of-band.

Why these, and not those

A2A v1.0 is a task and discovery protocol. It does not mint a new identity layer: it reuses OAuth, OIDC, mTLS, or API keys at the advertised endpoints. That is why OAuth shows up here and must not show up on the AAuth p2p row. AAuth identity-based access is signed HTTP with Signature-Key and no AS — different wire, different identifier. did:peer / DIDComm is pairwise wallet messaging; Agent Cards are globally fetched JSON. Do not forward caller credentials in-band down an A2A chain (A2A §7.6.3). Implicit and password grants on cards are deprecated.

Related flows

Sequence diagrams, not this topology cut. All flows

Comparisons

AAuth p2p

Agent provider (JWKS)AgentResourceUser (two-party)

AAuth identity-based / two-party (true p2p HTTP)

/patterns/aauth-p2p

No authorization server in the path. The agent signs the HTTP request; the resource decides from cryptographic identity (identity-based) or runs its own consent and issues a session (two-party). AAuth + RFC 9421 + Signature-Key. OAuth Bearer does not apply.

When you see it

Open-world HTTP clients that will not pre-register at every API's AS. A personal agent calling a small resource that is willing to trust an agent token and a signature. Two-party: the resource already has a login page and would rather issue its own session than stand up OAuth. Individual draft — pin a revision.

Actors and trust

  • AgentAgent instance

    Holds an aa-agent+jwt bound to its signing key. Identifier is portable (aauth:local@domain), not an AS client_id.

  • Agent providerOther

    Issues the agent token and hosts JWKS. The resource fetches keys; it does not call an AS token endpoint.

  • ResourceResource

    Verifies RFC 9421 + Signature-Key, then applies local policy. In two-party it also runs interaction and issues an opaque session.

  • User (two-party only)User

    Completes the resource's own page. May be ordinary OIDC behind that page; the agent never talks to that AS.

Topology

Agent provider (JWKS)AgentResourceUser (two-party)
  • Agent provider (JWKS)aa-agent+jwt bound to the signing keyAgent
  • AgentSignature-Key (jwt) + RFC 9421 Signature-Input/SignatureResource
  • ResourceFetch JWKS at iss / well-knownAgent provider (JWKS)
  • ResourceTwo-party only: resource-managed interactionUser (two-party)
  • ResourceAllow, or AAuth-Access session for subsequent signed callsAgent
Two HTTP parties. The agent signs; the resource verifies. No token endpoint in the path.

Primary

Optional

Do not use

  • Bearer tokens

    Bearer access tokens are not this hop. Do not present Authorization: Bearer as AAuth p2p.

  • OAuth 2.1

    No authorization server in the path. If you need one, that is interactive delegated, not p2p.

  • A2A (Agent2Agent)

    A2A is agent-to-agent tasks with Agent Cards. Different protocol.

  • did:peer

    Not globally resolvable; not a first-request HTTP identity.

  • DIDComm

    Messaging, not signed HTTP resource access.

Why these, and not those

The whole point of this row is that there is no AS minting a Bearer access token. Authentication is RFC 9421 over the HTTP request, with the key conveyed by Signature-Key (draft-hardt-httpbis-signature-key) carrying the agent JWT. Authorization is local policy on that identity, or a resource-issued session in two-party mode. Optional R3 and missions constrain what the agent may do without turning the hop into OAuth. Listing OAuth Bearer as applicable would describe a different pattern. A2A is a task protocol with advertised OAuth; did:peer is pairwise and not resolvable by a stranger. Keep all three apart.

Related flows

Sequence diagrams, not this topology cut. All flows

Comparisons

AAuth + person server

PersonPerson serverAgentResourceResource AS (four-party)

AAuth three/four-party with person server

/patterns/aauth-person-server

Portable agent identity plus a user grant from the person's server. Three-party: the resource has no AS. Four-party: the resource has an access server the PS federates to. OIDC may sit behind the PS to authenticate the person.

When you see it

A personal agent that carries the user's consent to resources that will never register it as an OAuth client. The user approves a mission at their person server once; the agent retries with an aa-auth+jwt. Four-party shows up when the resource already has a policy engine and will not evaluate auth tokens itself.

Actors and trust

  • AgentAgent instance

    Signs every HTTP call. Holds an agent token that names its person server (ps claim).

  • Person serverOther

    Represents the user: consent, missions, auth tokens, optional interaction. May authenticate the person with ordinary OIDC behind the scenes.

  • User / personUser

    Approves at the PS, not at each resource's OAuth screen.

  • ResourceResource

    Issues a resource token (aud = PS), then accepts aa-auth+jwt and applies its own policy to (iss, sub).

  • Resource access server (four-party)Other

    Optional. The PS federates to it; the agent still only talks to the resource and the PS.

Topology

PersonPerson serverAgentResourceResource AS (four-party)
  • AgentSigned request; resource sees ps on the agent tokenResource
  • Resource401 requirement=auth-token + resource token (aud = PS)Agent
  • AgentSigned POST of the resource tokenPerson server
  • PersonApprove mission / scope (OIDC may authenticate here)Person server
  • Person serverFour-party: PS federates to the resource access serverResource AS (four-party)
  • Person serveraa-auth+jwt (user claims, cnf-bound)Agent
  • AgentRetry signed, with auth tokenResource
Agent and resource still speak signed HTTP. The user grant comes from the person server. Four-party inserts a resource-side access server the PS talks to.

Primary

Optional

Do not use

Why these, and not those

You want AAuth's portable agent identity and a user grant, which identity-based p2p does not carry. The grant is aa-auth+jwt from the PS (short-lived, cnf-bound, aud = resource), not an OAuth Bearer access token from a client_id the resource minted. R3 and missions are the authorization language at the PS. Four-party adds a resource-side access server; that federation is not OpenID Federation and not OAuth identity chaining. OIDC belongs behind the PS (authenticate the person), not on the agent–resource hop.

Related flows

Sequence diagrams, not this topology cut. All flows

Comparisons

Multi-hop (one domain)

UserOrchestratorSpecialistAPISPIRE / WIMSE

Multi-hop on-behalf-of inside one domain

/patterns/multi-hop-obo

Orchestrator → specialist → API, still inside one trust domain. RFC 8693 act records who is acting. Transaction tokens carry immutable purpose. WIMSE re-binds the workload identity at each hop. AAuth call chaining (upstream_token / subagent_token) if you are already on AAuth.

When you see it

An orchestrator agent that fans out to a retrieval agent and a payments agent, all in the same cluster, all acting for the employee who started the task. Internal toolchains where every hop is your mesh. If the next hop is another company's AS, that is the cross-domain row.

Actors and trust

  • User (at the start)User

    Authorized the first agent. Must not be silently widened at a later hop.

  • Orchestrator agentAgent instance

    Holds the original grant. Exchanges or re-binds before calling specialists — does not forward the raw user access token.

  • Specialist / downstream APIResource

    Sees an attenuated token: subject = user, act = the calling agent, audience = itself, purpose unchanged.

  • Workload identity issuerWorkload

    SPIRE / WIMSE names each binary so a stolen user token presented by the wrong pod is a different incident.

Topology

UserOrchestratorSpecialistAPISPIRE / WIMSE
  • UserOriginal grant (OAuth or AAuth)Orchestrator
  • SPIRE / WIMSEWorkload identity for this binaryOrchestrator
  • SPIRE / WIMSEHop re-bind for the specialistSpecialist
  • OrchestratorRFC 8693 / txn-token / AAuth subagent_token — attenuatedSpecialist
  • SpecialistAudience-restricted, purpose-frozen callAPI
Same trust domain. Each hop attenuates and re-binds. The user grant does not travel as a raw Bearer token.

Primary

Optional

Do not use

  • Forwarding the original user access token

    Every hop becomes the user. No actor, no attenuation, no audience.

  • Expanding scopes at a hop

    On-behalf-of is a narrowing, not a promotion.

  • Identity chaining

    That draft is for crossing authorization servers / domains. Wrong row.

Why these, and not those

Inside one domain you do not need identity chaining across ASes. You do need a recorded actor (RFC 8693 act), a purpose that cannot grow (transaction tokens), and a workload identity that is re-bound at each hop (WIMSE). Agent-grants and AAP are individual OAuth profiles that try to say the same thing with extra claims — mark them draft/churn. If the fabric is AAuth, call chaining with upstream_token / subagent_token is the analogue: the sub-agent signs with its own key while nested act records the parent. Never expand scopes at a hop. Never forward the original user access token.

Related flows

Sequence diagrams, not this topology cut. All flows

Cross-domain chaining

UserAS AAgent in AAS BAPI in B

Cross-domain identity chaining

/patterns/cross-domain-chaining

The grant starts at AS A and must be accepted at AS B in another organization. Identity chaining (I-D) composes RFC 8693 and RFC 7523. RFC 9207 mix-up defenses exist because two issuers are now in play.

When you see it

An agent reads mail in the company tenant and files a ticket in a vendor SaaS whose AS is not yours. Partner integrations where each side has its own authorization server. Distinct from XAA only in that XAA is the IdP-brokered profile of a similar grant; this row is the general two-AS chain.

Actors and trust

  • Client in domain AAgent instance

    Holds a token from AS A. Must not present it at API C in domain B.

  • AS AOther

    Token-exchanges a JWT authorization grant audience-restricted to AS B.

  • AS BOther

    Redeems that JWT via RFC 7523 and issues an access token for its own resource. Must not be mixed up with AS A.

  • Resource in domain BResource

    Accepts only tokens from AS B, aud = itself.

Topology

UserAS AAgent in AAS BAPI in B
  • UserOriginal delegationAS A
  • Agent in ARFC 8693 exchange → JWT grant, aud = AS BAS A
  • Agent in ARFC 7523 JWT bearer grant (iss checks / RFC 9207)AS B
  • AS BAccess token for API CAgent in A
  • Agent in ACall in domain BAPI in B
Two ASes, two audiences. The client exchanges at A for a grant B will redeem. Mix-up defenses are mandatory.

Primary

Optional

Do not use

  • Transaction Tokens

    Same-domain context propagation, not a cross-AS grant.

  • Presenting AS A's access token at API C

    Wrong audience, wrong issuer, classic confused deputy.

  • A private cross-domain token format

    The chaining I-D exists so you do not invent one.

Why these, and not those

Two authorization servers means identity chaining, not a private JWT format and not a transaction token (txn-tokens are same-domain). RFC 8693 produces the grant; RFC 7523 is how B consumes a JWT assertion; the chaining I-D writes that down as a profile (RFC Editor queue as of July 2026 — no RFC number yet). RFC 9207 iss in the authorization response, plus exact issuer metadata checks, are how you stop mix-up when the client talks to more than one AS. XAA is the IdP-shaped variant; FAPI if B is high-risk.

Related flows

Sequence diagrams, not this topology cut. All flows

Mesh sidecar

SPIRE / WIMSE issuerSidecarAgent workloadOptional ASPeer API

Workload / mesh sidecar (unattended, no user)

/patterns/workload-sidecar

The agent is a binary in a mesh. SPIFFE/SPIRE names it, WIMSE WIT/WPT prove it, mTLS carries it. Client credentials or SPIFFE client auth if an AS is still in the picture. Not an OIDC user sub.

When you see it

An inference service in Kubernetes with a SPIRE agent (or mesh sidecar) issuing X.509-SVIDs. Internal tool-calling microservices with no human on the request. Sidecar proxies that present mTLS to the next hop so the app code never sees a static API key.

Actors and trust

  • Workload (agent binary)Workload

    Identified by a SPIFFE ID / WIMSE identifier. That string is 'payment-api in prod', not 'Alice'.

  • SPIRE / identity serverOther

    Attests the platform and issues short-lived SVIDs or WIT/WIC.

  • Sidecar / mesh proxyOther

    Often the process that actually presents mTLS. The workload identity is still the app's, not the proxy vendor's.

  • Relying workload / APIResource

    Authenticates the peer cert or WPT. Authorization is policy on the SPIFFE ID, optionally plus an OAuth client-credentials token.

Topology

SPIRE / WIMSE issuerSidecarAgent workloadOptional ASPeer API
  • SPIRE / WIMSE issuerX.509-SVID or WIT+WICAgent workload
  • Agent workloadWorkload API / identity for this podSidecar
  • SidecarmTLS / WPT / HTTP signaturesPeer API
  • Agent workloadOptional: SPIFFE client auth + client_credentialsOptional AS
Platform attests the binary. Sidecar or the app presents mTLS / WPT. Optional AS only for client-credentials, never for a user sub.

Optional

Do not use

  • OpenID Connect Core

    Do not put the user sub in the SPIFFE ID, and do not send an ID Token to the API.

  • Static API keys in the sidecar env

    The SVID is supposed to replace that.

Why these, and not those

There is no user on this hop, so OIDC user sub is the wrong identifier to stuff into a SPIFFE ID. SPIFFE/SPIRE is how production meshes already name binaries. WIMSE generalizes that across systems (WIT must not be used as Bearer; WPT or HTTP signatures or mTLS are the proof). If the API still wants OAuth, the client authenticates with SPIFFE (or mTLS RFC 8705) and uses the client-credentials grant — the token is the workload's, not Alice's. AIMS is the BCP that says this out loud. AAuth portable agent identity is a different scope (open-world HTTP clients, not your cluster).

Related flows

Sequence diagrams, not this topology cut. All flows

Host runtime

UserBrowser hostNative hostServer runtimeAuthorization server

Browser, native, and server-side agent hosts

/patterns/host-runtime

Where the OAuth client actually runs changes token storage and client type. RFC 10017 for browser-based hosts, RFC 8252 for native apps, confidential client + DPoP or mTLS for server-side runtimes. Same grant, different failure modes.

When you see it

A chat SPA that holds the agent's tokens in the page. A desktop companion (Claude Desktop, a CLI with a loopback redirect). A backend worker that is the confidential client and never shows tokens to the model or the browser. This row is orthogonal to the others: an interactive delegated agent is also one of these three hosts.

Actors and trust

  • HumanUser

    Still authenticates at the AS. The host type decides which user-agent and where tokens land afterwards.

  • Agent host (the OAuth client)Agent instance

    Public client in a browser or many native apps; confidential client on a server. Must not leak tokens into model context, logs, or XSS-reachable storage.

  • Authorization serverOther

    Enforces PKCE, exact redirect URIs, and (for confidential clients) client authentication.

Topology

UserBrowser hostNative hostServer runtimeAuthorization server
  • UserSPA / chat UI (RFC 10017)Browser host
  • UserSystem browser (RFC 8252)Native host
  • UserOptional; server holds the client keyServer runtime
  • Browser hostAuth code + PKCE; prefer BFF cookiesAuthorization server
  • Native hostAuth code + PKCE; claimed HTTPS or loopbackAuthorization server
  • Server runtimeConfidential client + DPoP or mTLSAuthorization server
Three places the same OAuth client can live. Pick one; do not mix their token-storage rules.

Three host runtimes

Browser-based agent host

The product UI is the OAuth client: a chat SPA, an embedded assistant, anything whose JavaScript could see a token.

UserBrowser agent hostOptional BFFASAPI
  • UserUses the chat UIBrowser agent host
  • Browser agent hostPrefer the BFF as the confidential clientOptional BFF
  • Optional BFFAuth code + PKCEAS
  • Optional BFFServer-side call; HTTP-only session cookie to the pageAPI
RFC 10017: PKCE always. Tokens belong in a BFF cookie or in memory — not in localStorage.

Token pitfall: XSS on the chat page is token theft. localStorage and sessionStorage survive XSS. Do not put access tokens in the DOM, in analytics, or in model prompts. Implicit flow is gone.

Native app host

Desktop or mobile companion: Claude Desktop, a CLI, an IDE plugin that opens a browser for login.

UserNative agent hostSystem browserAS
  • Native agent hostOpen authorize URLSystem browser
  • UserAuthenticate and consentSystem browser
  • System browserAuthorization code on claimed HTTPS or loopbackNative agent host
  • Native agent hostCode + PKCE exchangeAS
RFC 8252: system browser, PKCE, claimed HTTPS or loopback. No embedded webview.

Token pitfall: Embedded webviews are in-scope for phishing the password. Custom URI schemes are a last resort if claimed HTTPS is unavailable. OS token stores beat a plaintext file next to the binary.

Server-side agent runtime

The agent is a backend process. It can keep a client key. The browser, if any, never sees access tokens.

User (optional UI)Front end (no tokens)Server-side agentASAPI
  • User (optional UI)Session cookie onlyFront end (no tokens)
  • Server-side agentClient auth (private_key_jwt / mTLS) + user grant or client_credentialsAS
  • Server-side agentDPoP or mTLS-bound access tokenAPI
Confidential client. Authenticate with a key; sender-constrain the access token.

Token pitfall: Tokens in logs, traces, and tool arguments are the usual leak. Do not ship the client secret to the browser 'for convenience.' Do not hand the model the refresh token.

Primary

Optional

Do not use

  • Tokens in localStorage or the DOM

    XSS reads them. RFC 10017 is explicit.

  • Embedded webview for login

    RFC 8252: use the system browser.

  • Client secret in browser JavaScript

    There is no confidential client in the page.

Why these, and not those

OAuth 2.1 does not change the fact that browsers cannot hide secrets, native apps must not embed a webview, and servers can keep a key. RFC 10017 is the browser BCP: prefer a Backend-for-Frontend with HTTP-only cookies; if tokens must live in the page, keep them in memory, never localStorage. RFC 8252 is the native BCP: system browser, PKCE, claimed HTTPS or loopback redirects. Server-side agents are confidential clients and should sender-constrain with DPoP or mTLS so a leaked access token is not replayable from a laptop. Token storage is the incident: XSS in the chat page, an embedded webview, a refresh token in localStorage, or a token concatenated into a prompt.

Related flows

Sequence diagrams, not this topology cut. All flows

Unattended batch

Batch / cron agentSPIRE / issuerASAPI

Unattended batch / service agent

/patterns/unattended-batch

A cron, a queue worker, a service account with no human on the request. Client credentials and workload identity. Never the password grant. Never a long-lived user refresh token stuffed into the job.

When you see it

Nightly summarization over a corpus the service owns, a pipeline that classifies tickets as itself, a scheduled agent that calls internal APIs with a workload identity. If a human must approve a specific action, that is headless/async (CIBA), not this row.

Actors and trust

  • Service agentWorkload

    Acts as itself. Identified by client_id plus workload identity, not by a user sub.

  • Authorization server (optional)Other

    Issues a client-credentials access token audience-restricted to the API.

  • ResourceResource

    Authorizes a service account / SPIFFE ID. There is no 'on behalf of Alice' unless you moved to an OBO row.

Topology

Batch / cron agentSPIRE / issuerASAPI
  • SPIRE / issuerWorkload identityBatch / cron agent
  • Batch / cron agentclient_credentials (SPIFFE or mTLS client auth)AS
  • Batch / cron agentService-account call; aud = this APIAPI
No user. The job authenticates as itself — client credentials and/or a workload SVID — then calls the API.

Primary

Optional

Do not use

  • Resource Owner Password Credentials

    Never. Removed from OAuth 2.1.

  • Long-lived user refresh token in a cron

    That is someone else's grant, parked in a job. Use client credentials, or CIBA when a human must approve.

  • OpenID Connect Core

    No user on this hop. An ID Token is not an access token.

Why these, and not those

Client credentials (OAuth 2.1) and workload identity (SPIFFE/WIMSE) answer 'which robot is this?' They do not answer 'which human?' — and this row has no human. The password grant is gone (OAuth 2.1 / RFC 9700) and was always the wrong way to let a batch job impersonate someone. A long-lived user refresh token in a cron secret is delegated access with no session, no rotation story, and no way for the user to know the job is still running. If you need a user, use CIBA or an interactive grant at the time of action. AAP and AIMS are draft profiles/BCPs on this shape; treat them as churn.

Related flows

Sequence diagrams, not this topology cut. All flows

Adjacent, on purpose not a row

  • did:peer and DIDComm are not a row

    Pairwise, not globally resolvable, and not how a stranger's first HTTP call is authenticated. They sit in the catalog as adjacent identity/messaging. Do not substitute them for AAuth p2p, and do not substitute A2A Agent Cards for a DID document.

  • GNAP is finished, and not what these products speak

    RFC 9635 is a complete IETF alternative to OAuth. Interactive agent UIs, MCP HTTP, and A2A cards overwhelmingly profile OAuth 2.1 / OIDC instead. It is omitted as a primary protocol on every row below for that reason, not because it is invalid.