---
title: "How auth.md Standardises Agent Signup"
description: "auth.md is a new open protocol that gives agents a standard way to register with an API on a user's behalf, no human filling out a signup form. Here's how it works and why it matters."
canonicalUrl: "https://zuplo.com/blog/2026/05/28/auth-md-agent-signup"
pageType: "blog"
date: "2026-05-28"
authors: "martyn"
tags: "AI"
image: "https://zuplo.com/og?text=How%20auth.md%20Standardises%20Agent%20Signup"
---
Every API has an unspoken rule at the front door: a human signs up first. Fill
in an email, click a verification link, copy a key, paste it into your ~~code~~
env var. This is all good when humans are driving, but it's kind of a blocker
when it's an agent at the wheel.

[**auth.md**](https://workos.com/auth-md), a new open protocol shaped by the
folks at WorkOS, attempts to start the process of removing that wall. It's a
Markdown file an app hosts at its domain walking an agent through registering
for a credential, claiming it against a real user, and using it against the API.
Think `llms.txt` or `robots.txt`, but for "how do I get an API key for this
service."

<CalloutAudience
  variant="bestFor"
  items={[
    "API teams thinking about how AI agents will adopt their product",
    "Anyone watching the MCP / agent ecosystem and wondering what signup looks like in that world",
    "Platforms whose users want their agents to act for them without manual key copying",
  ]}
/>

## Why agent signup needs a protocol

When an agent (Claude Code, Cursor, opencode, whatever) wants to use an API on a
user's behalf, it has to obtain credentials. Today that means one of:

- The user signs up manually and sets the key up in a way that the agent can
  use.
- The agent walks the user through a browser-based OAuth dance designed for
  human screens.
- The user shares a long-lived personal token, a blast-radius problem the moment
  it leaks.

None scale to "my agent uses fifteen APIs to ship this task." The agent needs a
way to introduce itself, prove who its user is, and walk away with a credential
scoped to that user. That's what auth.md standardises.
[Managing API keys for AI agents](/blog/2026/04/20/managing-api-keys-for-ai-agents)
covers the same problem from the operator side.

## How agents discover auth.md

Discovery is two hops. An unauthenticated request to the API returns a 401 with
a `WWW-Authenticate: Bearer resource_metadata="..."` header pointing at the
[Protected Resource Metadata document](https://datatracker.ietf.org/doc/html/rfc9728)
at `/.well-known/oauth-protected-resource` on the API host. That document names
the API, its scopes, and the URL of its authorization server. The agent then
fetches `/.well-known/oauth-authorization-server` from that authorization
server, and finds the `agent_auth` block that points at the auth.md file and the
registration endpoints:

```json
{
  "agent_auth": {
    "skill": "https://service.com/auth.md",
    "register_uri": "https://auth.service.com/agent/auth",
    "claim_uri": "https://auth.service.com/agent/auth/claim",
    "revocation_uri": "https://auth.service.com/agent/auth/revoke",
    "identity_types_supported": ["anonymous", "identity_assertion"]
  }
}
```

The auth.md file itself is a procedural document: numbered steps saying
"discover the metadata, pick a registration method, register, claim, use the
credential, handle revoke." Written for an agent to read top-to-bottom. A short
excerpt from the spec's own auth.md gives you the flavour:

```markdown
## Step 3 — Register

Before sending an `identity_assertion` (either variant), surface the service's
`resource_name` and `resource_logo_uri` (from Step 1a) and the scope set you'll
be acting under, and confirm with the user. This is the user's only consent gate
before their identity is asserted to the service. Skip this for `anonymous`,
there is no user identity to assert.

### identity_assertion + id-jag

Mint the assertion with:

- `aud` = the `resource` from the PRM
- `iss` = your provider's issuer URL
- `email_verified: true` OR `phone_number_verified: true`
```

Imperative voice, conditional branches ("Skip this for…"), field references by
exact name. An agent can act on each line.

Crucially, auth.md doesn't ask you to rip out your existing auth. If you already
issue API keys, you keep issuing API keys. The protocol just gives an agent a
discoverable, machine-readable way to ask for one.

## Agent-verified vs user-claimed flows

The protocol defines two ways an agent can introduce its user:

|                   | Agent verified                                 | User claimed                                                 |
| ----------------- | ---------------------------------------------- | ------------------------------------------------------------ |
| Who vouches       | Agent's identity provider via signed JWT       | The user, via OTP                                            |
| Endpoint sequence | `register_uri` only                            | `register_uri`, then `claim_uri` start + complete            |
| Claim mechanism   | ID-JAG signature verified against issuer JWKS  | Email + one-time password                                    |
| Pre-claim scope   | Full scope on success                          | Reduced scope (spec example: `api.read`) until OTP completes |
| When to use       | Agent platform has a trusted identity provider | No identity provider vouching for anyone                     |

**Agent verified.** The agent's identity provider mints an
[ID-JAG](https://datatracker.ietf.org/doc/draft-ietf-oauth-identity-assertion-authz-grant/),
a JWT-shaped assertion saying "this user is X, audience is your service, signed
by us." The agent posts it to `register_uri`. Your service fetches the
provider's JWKS, verifies the signature, and issues a credential. If the
asserted user has no account, it's up to you: match an existing account, prompt
to claim afterwards, or refuse.

**User claimed.** The agent posts an anonymous registration to `register_uri`
and gets a credential with a reduced "pre-claim" scope. To bind it to a real
user, the agent posts the user's email to `claim_uri`, the service emails an
OTP, the human reads it back, the agent posts it to `claim_uri` again, and the
scope upgrades (the example adds `api.write`). Slower, but it works with no
provider vouching.

A service can support either or both.

## What auth.md means for API providers

**Credentials are bound to a user.** A post-claim credential is tied to the
human the agent acts for, keeping your per-user rate limits, billing, and audit
logs intact. The spec doesn't define a separate agent identity field, so
distinct credentials per agent for the same user are your handler's call, based
on ID-JAG issuer or session context. Same problem as
[provisioning API keys at first login](/blog/2026/05/08/provision-api-keys-at-first-login),
just triggered by an agent.

**The signup form stops being the bottleneck.** If an API is good at agentic
work but bad at frictionless signup, agents will route around it. A discoverable
auth.md is how you stop being the boring step.

**You stay in control of scopes.** The agent can only request what your auth.md
advertises, and you decide which flows you accept. Agent-verified from a trusted
provider is a different risk profile than an anonymous claim, and the protocol
lets you treat them differently. Until OTP completes, the credential is limited
to whatever read-only slice you advertised, so a never-claimed registration is a
read-only token sitting unused.

What auth.md _isn't_: a replacement for OAuth, a new token format, or
WorkOS-specific. The protocol composes existing standards (Protected Resource
Metadata, ID-JAGs) and is
[published on GitHub](https://github.com/workos/auth.md) under MIT.

## Implementing auth.md on your gateway

The spec is days old at the time of writing, the reference implementation is a
sample app, the "adopted by" list is short. But agents needing to register with
services on a user's behalf is a problem getting more real every month, and a
Markdown file at a well-known URL is the kind of low-ceremony primitive the
robots.txt / llms.txt / `/.well-known/` lineage suggests can spread.

Implementing it on the Zuplo side doesn't need a new policy, just a handful of
custom request handlers. Discovery endpoints are two small handlers returning
the metadata JSON. Registration and claim endpoints are
[custom request handlers](https://zuplo.com/docs/handlers/custom-handler)
wrapping your existing
[API key issuance](https://zuplo.com/docs/articles/api-key-management).
Revocation hangs off the same path backing your portal's "delete key" button.
The work is shaping your auth surface to match the spec, not building new auth.

<CalloutDoc
  title="Custom request handlers"
  description="Wrap your existing API key issuance behind the register_uri, claim_uri, and revocation_uri endpoints with TypeScript request handlers."
  href="https://zuplo.com/docs/handlers/custom-handler"
  icon="code"
/>

If you run an API you'd like agents to use without a human in the loop on every
signup, this is the conversation to be in. Read
[the protocol](https://github.com/workos/auth.md), look at your own auth flow,
and ask: what would my auth.md say?