Why your agent should never hold an OAuth token

An agent that holds a token can leak it through a prompt, a log or a transcript. Credential custody lets a platform act with the right account instead.

Illustration: A small friendly robot with a round camera-eye head stands at a service counter and hands over a folded paper order slip with empty hands otherwise.

An agent should never hold an OAuth token because everywhere the agent's text goes, the token can go too: prompts, tool results, logs, transcripts. The safer design is credential custody. The agent asks for an action, a platform performs it with the right account, and the token stays in the platform's custody. The agent receives tools, never the token.

The agent receives tools, never the token
The agent asks for an action. The platform performs it with the right account.
Agent
holds one credential: its CoreSpeed sign-in or key
CoreSpeed custody
stores the token, refreshes it, attaches it, records the call
App account
Notion, Slack, GitHub: the member's or the org's
The agent receives tools. The token stays in custody.

What goes wrong when the agent holds the token?

An agent is a process that reads untrusted text and then acts. That is its job. It is also the whole threat model.

Four things fail, in order of how often they happen.

Prompt injection. A fetched page, a post, a document or a mail can carry instructions. If the agent has a token in its environment or its config, one such instruction can ask the agent to print it, send it, or paste it into a tool call. The security guidance in the docs says to treat fetched content as untrusted for exactly this reason.

Logs and transcripts. Every tool call and result is recorded somewhere: the client's transcript, a CI log, a debugging dump. A token that sits in a header or a config file ends up in those records. Claude Code's claude mcp get prints headers, key included. One pasted transcript is one leaked credential.

Rotation. A provider token has a lifetime. When it rotates, every process that holds a copy needs the new one. With several agents on several machines, some copy is always stale.

Revocation. When a member leaves or a laptop is lost, someone has to find every copy. If the agent held the token, the copies are wherever the agent ran.

How does credential custody work?

In CoreSpeed, a connector is an app account a member or an organization already owns. CoreSpeed stores the credential, refreshes it when the provider allows, and exposes the connector's operations as namespaced MCP tools such as notion__create_page and slack__post_message. The agent calls the tool. The platform looks up the account, attaches the credential, performs the action, and records it in the activity trail.

What the agent seesWhat the platform holds
slack__post_message in tools/listthe workspace's access and refresh tokens
an account alias such as companythe provider account id behind the alias
a tool result, or an error codethe credential's state (needs_reauth or healthy)
the CoreSpeed key or sign-in it usednothing else about the provider

Three ways to connect end in the same stored connection. OAuth is the default: the member authorizes on the provider's consent screen, which names CoreSpeed as the client, and tokens are refreshed automatically. A pasted API key (Stripe is one) is stored encrypted; rotation is a reconnect, and disconnecting deletes CoreSpeed's copy only. An organization admin can also bring the organization's own OAuth app for vendors whose review gates a shared app, such as Google, Microsoft and Meta.

Several accounts of one app can sit side by side, each with an alias. Tools take an optional account argument. If more than one account is in scope and none is named, the call answers ambiguous_account with the aliases in structuredContent.error.aliases. No provider account id or token ever needs to appear in a prompt. The connectors page has the full detail.

What does the agent hold? One credential: its CoreSpeed sign-in or key. That is the honest trade. One revocable, capped, per-environment credential replaces a token for every app, and the inventory of what that credential reaches is one authenticated call:

curl https://api.corespeed.io/connectors -H "Authorization: Bearer $CORESPEED_API_KEY"

What happens when a token goes bad?

A refresh fails, or the vendor says the credential is invalid, or an organization's own OAuth app is replaced. The connection moves to needs_reauth. This is a recoverable state. The connector stays known, its tools stay visible in tools/list, and calls fail until the member reauthorizes in Dashboard → Connectors.

The agent's own credential is fine throughout. Do not rotate the CoreSpeed key and do not rewrite client configuration. The fix is one click by the member who owns the connection, and nothing about the agent changes.

For a pasted key, a rejected call does not flip the state on its own. The connection becomes needs_reauth only when the vendor names the credential with a standard code: invalid_token, invalid_client or invalid_grant.

Who can reach which account?

Custody also answers a question tokens cannot: on whose behalf is this call made?

Every connection is private, usable only by the member who connected it and that member's clients, or shared with the whole organization. A browser sign-in or an sk-cs- key acts as the member and reaches both. An sk-csa- agent key is an agent principal with an identity of its own. It reaches shared connections only, never a member's private ones. Its owner is the member who answers for it, and ownership is accountability, not permission: the agent inherits neither the owner's connections nor the owner's role.

Where a vendor can install CoreSpeed's app as its own actor, such as Slack's workspace bot, org-wide access is an organization integration that only an admin connects, and actions through it are attributed to the app. Each case lands in the activity trail under the identity that made it.

Is this where the industry is going?

Yes. When we introduced CoreSpeed we pointed at Cloudflare's August post on its own take on the pattern: credential-proxying "Gatekeepers", with agents never holding tokens. Different stacks, the same conclusion. Credential custody is trust infrastructure. The agent asks; something it cannot read acts.

FAQ

Does the agent see the token during a tool call? No. The call names a tool and an account alias. The platform attaches the credential on its side and returns the result.

What if a provider does not support OAuth? Paste the API key as a connection. It is stored encrypted with the same private-or-shared visibility, and rotating it is a reconnect.

What does the agent hold, then? Its CoreSpeed credential: a browser sign-in, an sk-cs- key or an sk-csa- agent key. Read it from an environment variable such as CORESPEED_API_KEY rather than a config file, and give an unattended agent a key with a monthly spend cap.

Can an agent reach a teammate's private Slack account? No. An agent principal reaches shared connections only. A member's sign-in reaches that member's private connections and the organization's shared ones.