Skip to content

Guide9 min read

OAuth connects the account. Policy governs the action.

An integration broker solves OAuth plumbing, but a connected account's scopes describe what the provider's API allows, not what your agent should do. Seven beliefs about brokered agent access that fail in practice, what the RFCs actually say, and the calls that test each seam.

IntertraceSecurity engineering

Field guides from Intertrace security engineering for the people who run AI programs.

October 14, 2026 · 9 min read

OAuthAgent AuthorizationIntegration BrokersMCPToken Exchange
Contents
  1. 01Myth: the connection went through OAuth, so the agent is governed
  2. 02Myth: what we requested at connection time is what we hold
  3. 03Myth: finer scopes will fix it
  4. 04Myth: the broker holds the token, so handing it to the agent is harmless
  5. 05Myth: if each component is correct, the path is correct
  6. 06Myth: a delegation chain carries the person's authority
  7. 07Myth: disabling the agent disconnects it
  8. 08What to ask the broker, and what Intertrace decides
  9. 09Six calls that show whether the seams hold

An agent is connected to the shared support mailbox through an integration broker. The demo goes well, and someone from security asks whether the agent can email anyone. The honest answer is yes. The connection holds a refresh token for a scope that lets the account send mail to any address, and nothing between the model and the provider checks the recipient. Everyone in the room had assumed that because the connection went through a proper OAuth flow, it was governed.

Brokers are worth using. They handle consent flows, token storage, refresh and the long tail of provider quirks, which is exactly the code you do not want every team to write. The mistake is reading the broker's success at authentication as authorization. That mistake survives on a handful of beliefs, each reasonable on its face. Here they are, with what the specifications actually say.

Myth: the connection went through OAuth, so the agent is governed

In OAuth 2.0, an access token represents "specific scopes and durations of access, granted by the resource owner" [1]. A scope is a space-delimited list of strings the provider defines, usually around API capabilities such as reading files or sending mail. That is the provider's vocabulary. Your business's vocabulary, which customer, which matter, which recipient, is not in it.

What the token allows versus what the task needsFig. 1
PROVIDER SCOPESend mail as this account, to anyoneBROKER CONNECTIONThis mailbox, refreshed for monthsTHE TASKReply to the senderof the current ticketTHE GAPAny other recipientallowed by the token,approved by nobodyPolicy checkat call timeasks or blocksa scope describes what the API can do for the account · the task, and the policy, describe what this agent should do

The provider scope lets the account send mail to anyone, the broker keeps that connection refreshed for months, and the task only needs replies to the ticket's sender. Everything between the inner and outer boxes is allowed by the token and approved by nobody, so a policy check has to decide there.

Consider Tessaly Legal, a fictional law firm whose intake agent reads a shared new-matters mailbox and can read every file its service account sees in the document store. A prospective client's email asks, in small grey text, for two recent matter summaries to be sent to a second address "for our general counsel." Every step is within scope: the store returns the summaries and the mailbox sends them anywhere. OAuth has done its job perfectly, and the firm is one model decision away from disclosing client material.

Myth: what we requested at connection time is what we hold

RFC 6749 lets the authorization server "fully or partially ignore the scope requested by the client," and when it issues a different scope it must return the scope actually granted [1]. After every reconnect, compare that returned value with what you expected, and hold the connection for an administrator if it widened. A migration that changes a provider's consent screen can widen what a reconnect grants, and this check is how you find out before the agent uses it.

The related habit is granting a broad scope up front "to avoid reconsent later," with narrowing promised later in application code. That is how a narrowing that was supposed to follow never ships.

Myth: finer scopes will fix it

The OAuth community has said plainly that scope is the wrong tool for this. RFC 9396, Rich Authorization Requests, introduces an authorization_details parameter because scope "is not sufficient to specify fine-grained authorization requirements," using examples such as a payment of a specific amount to a specific creditor [4]. Where a provider supports structured authorization details, use them. Most APIs agents connect to today do not, so the narrowing has to happen in your own path, before the call. The table is what that narrowing looks like for common connections.

What the connection grants versus what policy has to decide
ConnectionWhat the scope typically allowsWhat the task needsPolicy rule to enforce at call time
Shared support mailboxSend mail as the account to any addressReply to the sender of the current ticketRecipient must match the ticket requester; anything else asks a person
Document storeRead every file the account can seeRead files in the current matter or project folderPath or folder ID must belong to the case the task was opened for
Source repositoryPush to any branch the account can writeOpen a pull request from a working branchPushes to protected branches and force pushes ask or are blocked
CRMUpdate any field on any recordUpdate status and notes on one accountField allowlist and record bound to the account in the task
Payments APICreate refunds of any amountRefund one order up to a set ceilingAmount and order ID checked against the ceiling and the requester; above it, a person approves

Myth: the broker holds the token, so handing it to the agent is harmless

A well-built brokered path takes a normalized action from the agent, resolves the authenticated agent and its connection, checks policy against the action and its arguments, and only then lets the broker attach the credential and call the provider. The agent never sees the token. The decision record names the agent, the connection, the deciding rule and the provider request that resulted, so a reviewer can tell what was allowed from what actually happened.

Mediated path and the raw-token bypassFig. 2
MEDIATED PATHAgentholds no provider tokenPolicy checkaction + argumentsBrokerattaches credentialProvider APIaccount's scopeRaw token in agentexported by the brokertoken exportDIRECT CALL · NO POLICY CHECK · NO RECORDif the agent can hold the token, it can skip the check · keep credentials on the broker side of the decision

On the mediated path the agent's call is checked against policy before the broker attaches the credential and calls the provider. If the broker hands the agent a raw token instead, the agent can call the provider directly, with no policy check and no record of the decision.

Many brokers will also return the raw access token to the caller, which suits teams that want a provider's SDK. For an agent, that changes the control surface: the agent, or anything that can read its environment, can call the provider outside your policy and your audit trail. Sometimes the trade is acceptable. It is never compatible with a claim that every action is mediated, so document it, keep the token's scope minimal, and close the direct path with provider-side permissions or network controls where you can. The same goes for leaks you did not intend: keep tokens out of model context, prompts, routine traces and approval notifications, where a full request dump puts the credential in a channel many people can read. Log a connection ID and a masked account label instead.

Myth: if each component is correct, the path is correct

Every brokered call involves at least four identities: the tenant whose data is in play, the person who started the task, the agent making the call, and the provider account the token belongs to, often a shared operational account rather than the person's own. The expensive bugs live in the mappings between components. Identity resolves one tenant, policy checks a second connection, and the broker executes against a default account. Each piece passes its own tests.

  • Resolve the tenant on the server from the authenticated agent credential, never from an organization field in the request body or a tool argument.
  • Resolve the connection from the tenant's own bindings for that agent. A connection ID or provider account chosen by the model in a tool argument must be checked for ownership before use.
  • Record the person who started the task as a fact attached to the action, without granting the agent that person's standing access.
  • Treat whoever connects, reconnects or rescopes an integration as a privileged principal. Pointing a connection from a test workspace at production can matter more than any single call that follows.

Retries are the same kind of seam. After a broker timeout, a retry can send the same message or refund twice, because nobody reconciled whether the first attempt reached the provider.

Myth: a delegation chain carries the person's authority

RFC 8693, OAuth 2.0 Token Exchange, distinguishes two ways to represent an agent acting for a person. With impersonation, the actor becomes indistinguishable from the subject within the token's rights. With delegation, the actor "still has its own identity separate from" the subject, and the token carries both, with an act claim naming the current actor [3]. Prefer delegation where your authorization server supports it, because it keeps the agent visible in every downstream log. Token exchange can also request a token for one audience or resource, narrowing the credential to the service a call needs.

Two details limit what the chain proves. The may_act claim lets the authorization server check whether a party may act for the subject before issuing anything. And when act claims nest to show a chain of actors, only the top-level claims and the current actor are used for access control; prior actors are informational [3]. The chain is evidence. The receiving system still decides whether this agent may do this thing.

MCP servers that reach third-party APIs are where the shortcut creeps in. The current MCP authorization specification requires servers to validate that access tokens were issued specifically for them and says they "MUST NOT accept or transit any other tokens" [5]. An MCP server should never take a user's provider token from the client and forward it upstream. It should hold or obtain its own downstream credential and decide each call itself.

Myth: disabling the agent disconnects it

Refresh keeps a connection alive for months, and a shared connection outlives any one agent on it. RFC 9700, the OAuth 2.0 Security Best Current Practice, recommends audience-restricted access tokens limited to the minimum privileges required, sender-constrained tokens where possible, and refresh token rotation for public clients [2]. Apply those in whichever component owns each step, and add the rule that is specific to agents: disabling an agent removes its binding to every connection, and a still-active shared connection must not let a retired agent back in through a background refresh.

What to ask the broker, and what Intertrace decides

Before relying on a broker, get written answers. Can raw tokens be exported, and by whom? How are customers isolated, and how is a connection selected at call time? What audit events cover token retrieval, reconnects and scope changes? What happens on revocation, how quickly, and to queued calls when the broker is down? Anything undocumented becomes an integration test you write.

Intertrace's gateway sits inline on tool and MCP calls, derives the tenant from the agent's runtime key, and classifies each call from its arguments, raising the consequence tier and never lowering it. Roles keep outbound messages, payments and admin changes asking a person in one inbox, DLP inspects tool-call arguments, and the first call to an unapproved MCP server asks once. The broker still owns consent, token storage and refresh.

Six calls that show whether the seams hold

  • From an agent in tenant A, pass tenant B's connection ID in a tool argument. Expected: refused before any provider call, and logged.
  • Disable an agent while its shared connection stays active, then trigger a call and a refresh on its behalf. Expected: both fail for that agent and succeed for the others.
  • Ask the agent to mail an address other than the thread's sender. Expected: the call waits for a person or is refused, and the provider never sees it.
  • Try to retrieve the raw provider token from inside the agent's runtime. Expected: none is available, or the bypass is documented and the token minimally scoped.
  • Reconnect an integration with an extra scope added on the provider side. Expected: the widened grant is detected and the connection held for review.
  • Make the broker unavailable mid-task and let the agent retry. Expected: consequential calls stop or queue without duplicating a send or a refund.

Sources

Reporting, research and specifications this piece draws on. Links go to third-party sources; analysis and recommendations are Intertrace’s own.

  1. 01RFC 6749: The OAuth 2.0 Authorization Framework · IETF
  2. 02RFC 9700: Best Current Practice for OAuth 2.0 Security · IETF
  3. 03RFC 8693: OAuth 2.0 Token Exchange · IETF
  4. 04RFC 9396: OAuth 2.0 Rich Authorization Requests · IETF
  5. 05Model Context Protocol specification (2026-07-28): Authorization · Model Context Protocol

About this desk

Intertrace

Security engineering

Field guides from Intertrace security engineering for the people who run AI programs.

All 22 pieces by Intertrace

Dated October 14, 2026 · added to intertrace.ai October 17, 2026

+ Runtime enforcement

See these controls on your own agent traffic.

Intertrace sits inline between your agents and the models, tools and MCP servers they call, and decides every call before it runs.

Keep reading

All insights →