Skip to content

OAuth or API keys for AI agents?

Choosing OAuth or API keys for AI agents comes down to revocation: a grant is checked on every call, while a key works until someone rotates it.

Roopendra Talekar Updated 12 min read
A delegated OAuth grant checked on every call set beside a static API key that stays valid until an operator rotates it

OAuth or API keys for AI agents: what is the difference?

A contractor's last day was Friday. On Monday somebody in IT asks whether their AI access is gone. The answer was settled months earlier, by whoever set up the first assistant. Choosing OAuth or API keys for AI agents is that question in short form. It is about revocation before it is about authentication.

MCP (Model Context Protocol) is the standard way an AI assistant calls tools in other apps. An assistant that acts in your company's SaaS accounts holds one of two kinds of credential. The kind decides how fast you can stop it.

The first family is the static string: an API key, or a long-lived MCP connection token. Think of it as a password for a program. Whoever has a copy can use it, and the service at the other end cannot tell one holder from another.

The second family is the grant. A grant is a permission slip the service keeps on file, saying that this app may act for this named person within set limits. The service reads the slip when the app calls, so tearing it up is how you stop the app. OAuth is the sign-in flow that writes the slip: the person approves the app once, and the app never learns their password.

That design was the point. The OAuth 2.0 framework, RFC 6749, opens with the problem of third-party apps storing a person's password, often in clear text. It defines an authorization grant as a credential that represents the owner's approval. A static string carries no approval from anyone. Holding it is the approval.

What matters API key or connection token OAuth grant
What the agent holds A copy of the secret itself A token backed by a record the issuer keeps
Who a call names Whoever holds the string One person, acting through one client
How you take it back Rotate it at the issuer, then replace every copy Revoke the record; in Elaichi the next call fails
What a leaked copy reaches Everything the string can do, until rotation What that person's grant allows, until revocation
Needs a person present Never Once, to sign in

Most companies run both families at once and cannot say which is where. Assistants sign in. Scripts carry strings.

How does Zapier MCP issue each one?

Zapier MCP documents both families, and the split follows the client rather than anyone's preference. For most MCP clients, the member adds Zapier as a connector and signs in inside the client. Zapier creates the server during that sign-in, one per client. Clients not on Zapier's list, and code you write yourself, use a connection token instead. Zapier describes that token as long-lived and tied to one server, and says it "grants whoever holds it the ability to run the server's tools". Its guidance is to treat the token like a password, never distribute it, and keep one server and token per user rather than sharing. Every client connects to the same endpoint at mcp.zapier.com, so the URL is not itself a credential. Sources: the Zapier MCP quickstart and how connections work, checked October 2026.

So the precise statement is narrower than the one that gets repeated. Connection tokens are documented for code and for unlisted clients, and most clients sign in. Describing Zapier MCP as token-based across the board reads one page and skips the other.

In a company rollout of Zapier MCP, each member still signs in and runs tool calls as themselves. Admins can restrict members to a Zapier workspace, and app and action restrictions apply through MCP. A History tab shows user-level activity logs for tool calls. What the security page does not say is what happens to a member's server when that member leaves the Zapier account. That is a question to put to Zapier before a rollout, not a gap to assert. Sources: the rollout overview and the Zapier MCP security page, checked September 2026.

Whether each member should also get a server of their own is a separate design question.

What changes between revoking a grant and rotating a key?

Revoking a grant is one write at the issuer. Rotating a key or token means finding every string the person could have used, then replacing each copy that legitimate callers still need.

In Elaichi, removing or suspending a member revokes every live grant in the same transaction as the membership change. A grant here is the OAuth record that lets one client, signed in as one member, call the organization's MCP endpoint. Elaichi reads its revoked_at field fresh from the organization store on every call, with no cache in between. No token has to expire first, and every client that member pointed at the endpoint fails on its next request.

The OAuth standard for revocation names the gap to ask about. RFC 7009 defines how a client tells the issuer that a token is no longer needed. Revoking one token can take down the grant behind it as well. The RFC also concedes that in practice there can be a propagation delay, with some servers aware of a revocation and others not. So ask any vendor how its revocation flag is read, and whether anything caches it. A grant cached for an hour behaves like a key for that hour.

Not everything in Elaichi moves at grant speed, and writing otherwise is the usual mistake. Role membership and restrictions sit behind a 60-second cache, and a change also has to reach the edge. A restriction is a rule about which connectors and which individual tools a target may reach. A change to one takes effect within about two minutes, on MCP, the console and REST alike. Cut the person and the next call fails; narrow what the person may reach and the change lands inside that window.

Nothing happens to a static string until somebody rotates it. There is no per-call check to fail, because the string is the check. A key issued in March still works in October unless an operator replaced it.

Rotation is a distribution problem rather than an access-control one. The value sits in an environment file, a CI secret store, a laptop, a vendor's settings screen and often a chat thread. Copies also turn up in shell history and in a config file that was committed once and reverted. None of them reports back, so the issuer cannot count them. Until the last copy is replaced, rotation is an outage waiting for whichever caller you forgot.

That is not a flaw in one product. It is what a bearer credential is, which is why vendors who issue one say to treat it like a password. The price is that removing access becomes an inventory exercise across systems you do not control. The grant shape has a price too, a read on the hot path, and every call pays it for the sake of freshness.

What does a grant carry that a token does not?

A grant carries a person and a set of scopes, so the server decides on every call rather than once per string. A key carries whatever rights the issuer packed into it, and no person at all.

Scope is the first difference. Some vendors issue narrow keys per scope. Many issue one key with the account's full rights, so the agent gets more reach than its task needs. OAuth builds the limit in. Under RFC 6749, access tokens represent specific scopes and durations of access, granted by the owner and enforced by the servers.

Attribution is the second difference. A key has no person inside it. The third party's log shows the key, and a stranger holding it looks identical to the person who was meant to.

In Elaichi the grant then meets a ladder of checks. First comes the tool:execute permission, which gates the whole endpoint. Without it the tool list is empty, and any call fails with an error that names the missing permission. The Guest, Auditor and Billing Admin roles do not have it.

Four OAuth scopes sit underneath: mcp:read, mcp:write, mcp:destructive and mcp:tools. A tool classified forbidden is reachable under none of them. The mcp:tools scope does not replace the ladder, so deleting through a connected tool still needs mcp:destructive.

What a grant does not decide is reach. That is a separate layer, set by restrictions, which govern which connectors and which individual tools a target may reach. In Elaichi, restriction targets are role or user only; the organization default is the absence of a rule, which means allow everything. A rule aimed at a member can only narrow what their role allows, and never replaces or loosens a role rule. Blocks beat allows. Before writing a first rule, read why a block matches a tool's name but an allow matches only its operation.

Why does the model never see the connector secret?

Elaichi never hands the connector secret to the model, or to the client. A key given to a model sits in the context window, where it can be echoed into an answer or into a shared transcript.

Connector credentials are not stored in Elaichi at all. Each account's secret lives with a separate credential service, encrypted with AES-256-GCM at rest, and that service owns refresh. When a refresh fails, the connection is marked needs_reauth, so a stale account shows up as stale instead of failing quietly. For the connectors Elaichi authors, no third-party MCP server sits in the path to receive the secret. A native MCP connector's server is the app vendor's own, and Elaichi never forwards its own access token to it.

What the client holds is the grant. Elaichi serves one organization-wide MCP endpoint, POST /mcp, behind OAuth, and Claude, ChatGPT and Cursor all point at the same address. Each member connects once and signs in with a grant of their own. The address carries no secret and is identical for everyone; the grant behind it is what differs. That is the shape the MCP authorization spec asks for. It requires the token in an Authorization header on every HTTP request, and it forbids putting a token in the URL's query string.

A connect URL is a one-time session with no token inside it, so it is safe to hand back over MCP. Mistaking a setup link for a credential is a common error.

An organization can bring its own OAuth app per connector. The accepted body is client_id, client_secret and scopes, and nothing shaped like an endpoint can be expressed. Changing it requires connector:manage rather than connection:manage. Somebody allowed to delete a connection therefore cannot also repoint the organization's OAuth app.

One limit belongs in this section, stated plainly. The prompt-injection write gate lives in the Elaichi agent window and does not apply to a raw tool call. An MCP server never sees the user's prompt, so keeping a secret out of the prompt does nothing against injection. What the endpoint does enforce is a permission check per operation, the forbidden class, output redaction, the grant's scopes and a record of every call that reaches execution.

Who gets a grant in the first place?

A grant is only as trustworthy as the sign-in that produced it. In Elaichi that sign-in can be Google, GitHub or Microsoft, an email code, TOTP MFA with single-use recovery codes, or a passkey.

Enterprise SSO (signing in through the company's identity provider) over SAML and OIDC is built in-house. SCIM v2, the standard an identity provider uses to create and remove accounts, covers users and groups, and groups map to roles. A domain verified by DNS TXT record lets new colleagues auto-join with a configurable default role.

Elaichi's own API tokens get the handling any long-lived secret needs. They are hashed at rest and shown once, so the value on screen is the only copy. The record of each action stores actor_kind as a field rather than an inference, with values including user, api_token and ai_assistant, which marks the Elaichi Agent. Token traffic stays separable from human traffic without anyone guessing from a user agent.

What happens when you remove somebody from the organization?

In Elaichi, access stops on the next call. The reason is structural: removing or suspending a member revokes every live grant in the same transaction as the membership change. The static strings that person created or copied are untouched, and they are the slow half of the job.

The order that works:

  1. Suspend or remove the member in Elaichi. The next call from any client they used fails.
  2. If the person stays but their reach was wrong, write a restriction against their role or against them as a user. Allow about two minutes for it to take effect.
  3. Rotate every API key and connection token at its issuer, then replace each copy in environment files, CI stores and vendor screens. No membership change reaches these, and no control plane shortens this step.
  4. Filter the audit trail by actor and time window to see what ran before the cut. Rows are eventually consistent, so the newest can lag by a moment.

Elaichi will not complete a removal blindly. A toolbox is a named bundle of tools and the accounts they run against. A preflight refuses a removal while one of the person's private connections is still relied on by a shared toolbox. Transfer that connection to another active member, or delete it. A transfer goes to one member, never to a team or the organization. A private connection that nothing beyond the person depends on cannot be transferred and is deleted with them. Delegated toolbox entries raise a warning that does not block, and re-pinning them is the fix.

Removal also stays tractable at company scale because there is only one address. Every member reaches the same endpoint, so there is no per-user server to find and delete. The grant is the only per-person piece. A leaver's offboarding, step by step covers the full sequence when connections are still in use.

What does the audit trail show after access is cut?

Revocation settles what happens next. The record settles what already happened, and the two credential families leave different evidence behind.

A static string identifies itself, not a person. When two scripts share one key, the third party's log credits both calls to that key. Who sat behind each call then becomes a guess from addresses and timing.

A grant names a member, so the trail can name one too. Elaichi writes one entry for each connected-tool call that reaches execution (a call refused earlier writes none). A member who has left still shows as "Former member" instead of vanishing, and what an agent's audit row should hold has its own post.

When is a long-lived key or token still the right answer?

When there is no browser and no person present to sign in. That covers more callers than people expect.

A nightly sync, a CI step, a script on a server and code written against an endpoint cannot complete an interactive sign-in on a schedule. A grant needs somebody present the first time, and a headless caller has nobody there at 3am. The MCP authorization spec makes the same concession for local servers. Its OAuth flow is written for HTTP transports. A server running over STDIO, launched by the client as a local program, is told to take credentials from the environment instead.

The second case is the third party itself. Plenty of vendors issue nothing but keys. When that is all there is, Elaichi's credential service stores the value encrypted. Reading the configuration back returns the public values plus secret_paths: the dot-paths that were encrypted, with none of their values. That list alone decides whether a variable counts as a secret. An edit to an encrypted value through read-back is refused. The refusal reads the same whichever side produced it, so probing teaches a caller nothing.

A prototype belongs here too, and so does a client that is not on any vendor's supported list.

Take the trade knowingly. You gain a caller that runs without a person. You accept secure storage, the narrowest scope the issuer offers, a named owner and a rotation schedule.

How do you check what you have today?

Run this before deciding anything. It takes an afternoon, and it usually surprises people.

  1. List every MCP client in use: Claude, ChatGPT, Cursor and anything a developer wired up directly.
  2. For each one, note whether it signed in with OAuth or was handed a static string.
  3. For every static string, find the other copies: CI, shell history, shared documents, a teammate's machine.
  4. Pick one person who left last quarter and call their access path. Do not ask whether it was revoked.
  5. Time how long a permission change takes to reach the tool surface, and test that number rather than quoting a vendor page.

Step four is the one that changes minds. If a leaver's path still works, the credential was a bearer string and nobody rotated it.

When do you not need a control plane for this?

When one person uses one assistant against one personal account. Sign in with OAuth inside the client, and revoke the grant in the vendor's own settings page when you are done. There is no organization to answer to and no second account to mix up.

A single developer's key in a local environment file is the same story. The blast radius is one human, and the revocation plan is to rotate the key and tell nobody, because nobody else has it. Adding a control plane to that is work with no return.

The calculation changes at two moments: the first leaver, and the first reviewer who asks to see what an agent did. The argument for not buying yet sets out where that line sits. If the open question is who should run the server that holds the credential, the operating cost of self-hosting MCP servers covers it. The connector catalog lists what each account can be connected as, and the security overview covers residency, customer-managed keys and the audit trail.

FAQ

Frequently asked questions

What is the difference between OAuth and API keys for AI agents?

An OAuth grant is a record the issuer keeps, saying that a named client may act for a named person within set scopes. It can be marked revoked at the issuer, and in Elaichi the agent's next call then fails. An API key is a string whose possession is the authorization. It stays valid until somebody rotates it at the issuer, after which every caller still holding the old value breaks until it is updated. It carries no identity of the person behind the call.

What is the difference between an MCP connection token and an OAuth grant?

A connection token is a long-lived bearer string, in the same family as an API key. Whoever holds a copy can run the tools behind it, so taking it back means rotating it and then updating every caller that still needs it. An OAuth grant is a record on the server, tied to one member and one client. In Elaichi, removing or suspending a member revokes every live grant in the same transaction as the membership change, and the revocation field is re-read on every call, so access ends with the next request.

How quickly does revoking an AI agent's access take effect in Elaichi?

Grant revocation, member removal and member suspension are effective on the next call, because Elaichi re-reads the revocation field from the organization store on every call with no cache. Role membership and restriction changes work differently. They sit behind a 60-second cache and also have to reach the edge, so they take effect within about two minutes across MCP, the console and REST.

When should an AI agent still use a long-lived API key or token?

When there is no browser and no person present to complete a sign-in. Nightly jobs, CI steps and code written against an endpoint cannot produce an interactive OAuth consent on a schedule, and the MCP specification itself tells local STDIO servers to take credentials from the environment. A key is also the only option when the third party issues nothing else. Give it the narrowest scope the issuer offers, plus a named owner responsible for rotating it.

Does Zapier MCP require a connection token?

Not for most clients. Zapier documents that for most MCP clients the member adds Zapier as a connector and signs in inside the client, and Zapier creates the server during that sign-in. Connection tokens are documented for clients not on Zapier's list and for code you write yourself. Zapier describes those tokens as long-lived and tied to one server, and says to treat one like a password (docs.zapier.com, checked October 2026).

Is an MCP server URL or a connect URL a credential?

A bare server address is not, but a URL with a token embedded in it is. The MCP authorization specification forbids putting access tokens in a URL's query string and requires them in a header on every request. Zapier says its mcp.zapier.com endpoint is not a credential; the connection token is. In Elaichi the address is one organization-wide endpoint behind OAuth, and a connect URL is a one-time session that carries no token. Guard the token or grant behind an address, not the address itself.

Put agents to work on your own systems

14 days on Gold, no credit card. Start with one app and one team.

Works with
Claude ChatGPT Cursor and any other MCP client, or the Elaichi Agent.
When the trial ends
Nothing is deleted. Connections, roles and the audit log stay where they are, so subscribing picks up exactly where you left off.