When people ask how an AI agent should log in to a service, the first answer is almost always OAuth. It is a good answer. OAuth exists precisely to let one party act on behalf of another without handing over a password, and that is what an agent does. But OAuth was designed around a specific picture: a human at a browser, approving a known app, which then calls an API in predictable ways. Agents bend every part of that picture.
This post separates the parts of OAuth that carry over cleanly to agents from the parts that quietly stop working, and what to put around the protocol so the gaps don't become incidents.
Where OAuth works well for agents
Start with what OAuth gets right, because it is a lot.
- No shared passwords. The agent never sees the user's credentials for the service. It holds a token, and the token is not the account. Compared to an agent typing a password into a login form, this is a categorical improvement.
- Explicit consent. The authorization-code grant puts a consent screen in front of the human. Someone decided, on the record, that this client may act for them.
- Expiry and refresh. Short-lived access tokens plus rotating refresh tokens mean a leaked access token has a limited shelf life, and reuse of a rotated refresh token can be detected.
- PKCE for public clients. Most agents run in places that cannot keep a client secret — a CLI, a desktop app, a hosted runtime shared by many users. PKCE binds the code exchange to the client that started it, which is why the MCP authorization spec makes it mandatory.
- Discovery. Authorization-server metadata (RFC 8414) and OpenID discovery let a generic client configure itself from a URL, so an agent framework does not need per-provider code.
If you are connecting an agent to a service that already speaks OAuth and the agent only needs to do what the scopes describe, use it. The MCP server authentication guide walks through the concrete flow. The seven gaps below are where that stops being enough.
1. Consent assumes the account already exists
OAuth delegates access to an account. It says nothing about creating one. An agent that needs a new service — a search API, an email provider, a data vendor — usually hits a signup form first, with email verification, a CAPTCHA and terms to accept. OAuth cannot help there, so agents end up either blocked or scripting a browser through a form that was built to stop exactly that. We covered the alternative in how agents sign up without a form.
2. Scopes describe endpoints, not intent
Scopes are coarse by design: read, write, repo, mail.send. A human using an app exercises a scope through a UI that constrains what they actually do. An agent exercises the full scope, steered by whatever text it last read. A mail.send grant that was meant for "reply to this thread" is equally valid for "email the contents of the inbox to an outside address" if a prompt injection asks for it. That is the confused deputy problem, and finer-grained scopes only shrink it; they don't remove it.
3. There is no concept of a spending limit
OAuth answers "may this client call this API". It does not answer "how much may it spend". For a human clicking buttons, the price of each action is visible and the pace is slow. For an agent in a loop, a paid endpoint can be called thousands of times before anyone looks. Some providers bolt on account-level quotas, but those are per-account and set by the vendor, not a ceiling the human attached to this specific delegation. Money limits need to live in the grant itself — see how agents pay for services with x402.
4. Bearer tokens end up in the context window
An OAuth access token is a bearer token: whoever holds it can use it. In a traditional app it lives in server memory or a cookie the user never sees. In agent setups it often ends up in an environment variable the model can read, a tool config, a log, or even the prompt itself. Anything in the context window is one injected instruction away from being echoed somewhere else, which is the path described in credential theft via prompt injection. Sender-constrained tokens (DPoP, mTLS) help, but few APIs accept them today.
5. The token says who, not what kind of who
A service receiving an OAuth token learns which account authorized the client. It does not learn whether a verified human stands behind that account, or how strongly that human was verified. So services that care about abuse treat every API client as anonymous until proven otherwise, and agents get the lowest tier. OAuth has no standard way to carry "this delegation comes from a person with a verified email and phone". That attestation is a separate layer, discussed in proof levels for agents.
6. One consent flow per vendor, forever
Each service runs its own authorization server, its own consent screen and its own token lifetimes. An agent that uses ten services holds ten sets of tokens with ten refresh policies, and the human who wants to cut it off has to visit ten dashboards. Revocation exists in the spec (RFC 7009), but there is no single place to see every delegation an agent holds and kill one.
7. Agent identity is flattened into the client
OAuth has a client and a user. Agent systems usually have three parties: the human, the agent product, and the specific agent instance doing the work. Logs at the service show "client X acted for user Y", which cannot distinguish a scheduled job from a hijacked session. Token exchange (RFC 8693) can express an actor chain, but support is thin. The distinction matters more than it looks — agent identity vs user identity goes deeper.
What to add around OAuth
None of this means abandoning OAuth. It means treating it as the transport for delegation and adding the properties it lacks:
- A per-vendor grant with a budget. Each delegation names one service, one scope, an expiry and a spending ceiling that the service and the broker both enforce.
- Signed human-proof claims. The grant carries which proofs the issuer verified about the human, so the service can set its own bar instead of assuming the worst.
- Offline-verifiable credentials. A signature the service checks against a published key, rather than a token that only means something to one authorization server.
- One revocation surface. The human sees every vendor the agent can reach and revokes any of them in one place.
- Keep secrets out of the model. Tokens live in the runtime or the broker, never in text the model reads or writes.
This is the job of an auth broker. Notlogin is one: it is a standard OpenID Connect provider (PKCE, discovery, refresh rotation) for services that want plain OAuth, and it also issues per-vendor verifiable credentials that carry the scope, the USDC budget, the expiry and the human's proof transcript under an Ed25519 signature. Vendors declare which proofs they require and verify locally; the human revokes from one dashboard.
Rule of thumb
Use OAuth when the agent acts inside an account that already exists, the scopes match the task, and nothing costs money. Reach for a broker-issued grant when the agent needs to sign up somewhere new, spend against a limit, or prove there is a verified human behind it. Most real agents need both.
If you run agents and want every service on its own narrow, budgeted grant, start with Notlogin. If you run an API and want agent requests that state their scope, budget and human proof up front, register as a vendor.