Empyre / Articles / OAuth for autonomous software

Giving AI agents an identity

An agent that does anything useful on a user's behalf needs authority from that user. The lazy answer — give it the password — hands over everything, permanently, with no record of what it did and no way to take it back.

OAuth solved this for applications a decade ago. Agents do not break that model, but they stress it in a specific place, and the difference is worth understanding before you build on it.

The assumption OAuth was built on

Classic OAuth assumes a human is present at authorisation and mostly absent afterwards. You click Allow, the app gets a token, and the interesting security event — the consent — happens while you are watching.

Agents invert the ratio. The human authorises once, then the agent acts repeatedly, unattended, possibly for months. The consent is a single moment; the exercise of it is continuous.

That inversion does not require new cryptography. It changes which of the existing controls actually carry weight.

What matters more for agents than for apps

Scope, because nobody is watching

For an interactive app, over-broad scope is mitigated by the user being there. For an unattended agent it is not mitigated by anything. The authority you grant is the authority that gets exercised, at machine speed, while you sleep.

Rotation, because credentials live longer

A months-long agent session is a months-long liability. Refresh rotation — each refresh issuing a new token and invalidating the old — bounds how long a stolen credential stays useful.

Replay detection, because reuse means theft

If a refresh token is presented twice, one of those presentations was not you. The correct response is to revoke the entire token family, not to serve the request. This is the control most often skipped.

Revocation that fails closed

When the token service cannot be reached, the answer must be deny. A system that fails open turns an outage into an authorisation bypass, and outages are exactly when nobody is looking.

PKCE regardless of client type

Agents are frequently public clients, and whether a given deployment is confidential is a detail that changes without anyone updating the security model. Requiring S256 everywhere removes the question.

The thing people get wrong

The most common mistake is not weak crypto — it is treating the agent as the user. If your system cannot distinguish “Alice” from “an agent acting for Alice, within these limits, since Tuesday”, then you cannot scope it, cannot audit it, and cannot revoke the agent without locking out Alice.

That distinction has to exist in the data model, not in a naming convention. Everything else — scopes, audit, revocation — is downstream of it.

What this looks like in practice

Relay implements the list above as defaults rather than options. An agent exchanges its own credential pair for a short-lived, scoped token:

import { RelayClient } from "@empyre/relay-sdk";

const relay = new RelayClient({ audience: "example.com" });

const result = await relay.authenticateAgent(
  process.env.RELAY_AGENT_ID,
  process.env.RELAY_AGENT_SECRET,
);

if ("status" in result && result.status === "pending_approval") {
  // The owner gets a one-tap approval email. Retry after approval.
} else {
  // Short-lived, scoped, revocable.
  useToken(result.access_token);
}

Should you just use Auth0, Clerk or Okta?

If you already run one — probably yes, and this is not a close call. They are mature, audited, and they work. Migrating an identity layer to chase defaults is rarely the right trade.

The honest difference is shape rather than strength. Those providers are built around human login journeys, so the agent-specific behaviours are things you configure. Relay's position is that for agents they should not be configurable, because the failure mode of getting them wrong is silent.

More detail at OAuth for AI agents.

Frequently asked questions

Can I just use an API key for my agent?

For a single-tenant internal tool, often yes. It breaks down the moment the agent acts on behalf of many users: an API key expresses no user consent, no per-user scope, and no way to revoke one user's authority without revoking everyone's.

What happens if an agent's token leaks?

With short expiry, scoping and rotation, the blast radius is bounded and the credential expires on its own. Without them, a leaked long-lived credential is valid until someone notices — and for unattended agents, nobody is watching to notice.

Why revoke the whole token family on a replay?

Because a second use of a single-use token means it was captured. Serving that request assumes the least likely explanation. Ending the session costs a re-authorisation; not ending it costs the account.

Try Empyre free

Describe a business in plain words and watch eight AI agents build and deploy it. The first build is free — no card required.

Start free →

Related

OAuth for AI agentsHow AI agents leak API keysRelay docsAll articles