auth.md: a reference build for agentic registration
An open protocol that lets agents register for services on behalf of users — discoverable through a Markdown file at your domain.
At a glance
- What is it?
- WorkOS auth.md is a TypeScript reference implementation of agentic registration, where an agent authenticates to a service on behalf of a user across three defined roles, with a sample service, a sample agent IdP and a Markdown manifest the service hosts.
- Who is it for?
- auth.md is worth reading if you are designing auth for agent-facing products and want the ownership ceremony drawn out before you pick a vendor. It will not hand you a production identity provider: the assertion grant is still a draft, the claim grant carries a vendor namespace, and the sample servers exist to be read rather than deployed.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 11 days ago.
- What is it written in?
- Mainly TypeScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 5, 2026, and from our analysis. They are not legal advice.
Editorial analysis
Three roles, and only the service mints the assertion
Agentic registration has three roles, and the direction of trust is fixed before any code runs. An agent acts on behalf of a user. An agent provider mints identity assertions in the ID-JAG shape, tracked as the draft identity assertion authorization grant at the IETF datatracker. A service accepts those assertions when it can, and issues credentials. The service never takes the agent at its word about who the user is. It either validates an assertion the provider minted, or it runs a claim ceremony, and two ordinary conditions push a registration onto that second path: the agent is not associated with a user identity at all, or the agent provider does not support ID-JAGs. Anything that cannot produce a provider-signed assertion falls back to an RFC 8628-style ceremony where the human proves ownership out of band. Both halves ship in one tree here, as a sample provider and a sample service, so you can read the two sides against each other instead of guessing what the other side does.
Registration and credential issuance are two separate endpoints
The sample service splits registration from credential issuance, and that split is the whole trick. `POST /agent/identity` accepts the identity assertion the agent chose, where the accepted types are an ID-JAG, a verified email, or anonymous. It answers with a service-signed `identity_assertion`. The agent then presents that assertion at `POST /oauth2/token` under the RFC 7523 JWT-bearer grant and receives an `access_token`. Nothing is authorized at registration time. Registration produces an assertion, and the token endpoint decides what that assertion is worth. Because the assertion is signed by the service, the exchange never has to trust the agent a second time. A caller that skips `POST /agent/identity` has nothing to send to `POST /oauth2/token`, so the two endpoints cannot be swapped or merged without changing what the service is attesting to. If you are writing the client side, that ordering is the contract: discover, register, exchange, and only then call anything.
The agent_auth block is where the standard metadata stops
Discovery lives at `/.well-known/oauth-authorization-server`, and the sample document mixes two vocabularies on purpose. `issuer`, `token_endpoint`, `revocation_endpoint` and `grant_types_supported` are the standard fields from RFC 8414, RFC 7009 and RFC 7523, sitting alongside the familiar `resource`, `authorization_servers`, `scopes_supported` and `bearer_methods_supported`. The sample advertises two scopes, `api.read` and `api.write`, and a single bearer method, `header`. Then comes `agent_auth`, which is named as the profile extension carrying the registration and claim surface. That one nested object is where an agent learns that this server accepts agent registration at all, and it is also where any later change to the ceremony would land without touching the standard fields. The grant list is where the two worlds meet: beside the standard `urn:ietf:params:oauth:grant-type:jwt-bearer` there is a namespaced `urn:workos:agent-auth:grant-type:claim` for the ceremony path.
Anonymous registration hands out a pre-claim scope and waits
The anonymous flow shows the protocol's real position on unknown identity. The agent posts an anonymous identity type to `POST /agent/identity` and receives two things back: an `identity_assertion` and a `claim_token`. It exchanges the assertion at `POST /oauth2/token` with the jwt-bearer grant and gets an access token whose scopes are pre-claim. The agent works inside that reduced permission set until somebody claims ownership. Claiming starts at `POST /agent/identity/claim` with the `claim_token` and an email address, and the service replies with a claim attempt carrying a `user_code` and a verification URI. Nothing here is a shortcut around identity. An anonymous agent does get credentials immediately, but those credentials are deliberately incomplete, and the upgrade requires a human to prove they own the address. That is a narrower failure mode than refusing to issue anything, and a very different one from trusting the claim outright.
The verified email path puts a human in front of the token endpoint
When the agent has an email address but no provider assertion, the service runs the ceremony with the user in the loop. The agent posts `type: service_auth` with a `login_hint` of the email, and the reply carries a `claim_token` plus a claim made of a `user_code` and a `verification_uri`. The agent surfaces both values to the user instead of opening anything itself. The user signs in at that URI, lands on a `/claim` page, and posts a `claim_attempt_token` with the `user_code` to `POST /agent/identity/claim/complete`. Meanwhile the agent polls `POST /oauth2/token` with the claim grant and its `claim_token`, looping until the claim lands. Two things follow from that shape. The agent never touches the user's credentials, and the service alone decides what a completed claim is worth. The sequence diagram for this flow stops partway through, so the steps after the visible ones are not written down.
Four workspace packages under a private root marked 0.6.0
The layout is a pnpm workspace with four packages, and the root package.json is marked private, so nothing here is meant to be installed as a library:
.
├── AUTH.md ← skill manifest agents read
├── agent-services/ ← sample resource server + authorization server
├── agent-providers/ ← sample agent IdP that mints ID-JAGs
└── shared/ ← shared workspace package (ports, types)`AUTH.md` is the sample skill manifest a service would host, giving the procedural recipe in six steps: discover, register, claim, exchange, use, then handle revoke. `agent-services/` holds a sample resource server plus authorization server, `agent-providers/` a sample agent IdP that mints ID-JAGs, publishes JWKS and sends revocation events, and `shared/` the workspace package carrying ports and types. The root scripts are the operational surface. `dev` builds `shared` first, then runs both sides concurrently under the names agent-provider and agent-service; `dev:service` and `dev:provider` start one side only; `typecheck` and `build` recurse across the workspace; `format` and `format:check` drive Prettier against both ignore files. The toolchain is pinned to `[email protected]`, with `concurrently` and `prettier` as the only dev dependencies.
Two local ports and a home page that walks all three flows
The quickstart is two commands:
pnpm install
pnpm devThe service listens on `http://localhost:8000` and the provider on `http://localhost:4000`. The service home page walks the three registration flows interactively, which is the fastest way to see the ID-JAG, verified email and anonymous paths next to each other rather than as three separate documents. The one-side-at-a-time scripts exist because the flows cross the two processes: in the ID-JAG path the assertion is minted by the provider at 4000 and redeemed by the service at 8000, so running only one side leaves you halfway through a sequence. Both README files that the root page routes you to carry the detail this page does not, with sequence diagrams and error tables for the service side and the minting, JWKS and revocation instructions on the provider side.
One draft grant, one vendor grant, and no published release
The identity assertion the design leans on is a draft, the identity assertion authorization grant still sitting in the IETF datatracker. The fallback is described as RFC 8628-style rather than as an implementation of RFC 8628, and the claim path uses a grant with the vendor namespace in it, `urn:workos:agent-auth:grant-type:claim`. That combination is the honest shape of the thing: a reference implementation with sample servers on both sides, not a deployed service and not a finished standard. There are no GitHub releases for the repository even though package.json carries version 0.6.0, so that number is a workspace-internal counter rather than something you can install. The last push was on 2026-09-24, the license is MIT, and the primary language is TypeScript. Anyone adopting the shape should plan for the grant names to move.
Editorial conclusion
auth.md is worth reading if you are designing auth for agent-facing products and want the ownership ceremony drawn out before you pick a vendor. It will not hand you a production identity provider: the assertion grant is still a draft, the claim grant carries a vendor namespace, and the sample servers exist to be read rather than deployed. If you continue, read agent-services/README.md and agent-providers/README.md, run pnpm dev to watch the three flows on localhost:8000 and localhost:4000, then decide whether a pre-claim scope plus a user code fits the way your product already thinks about sign-in.
Frequently asked questions
What is auth.md in the workos/auth.md repository?
auth.md is a reference implementation of agentic registration, a protocol in which an agent authenticates to a service on behalf of a user, shipped with a sample AUTH.md file that the service would host to tell agents how to authenticate.
Which three roles does the auth.md protocol define?
An agent acting for a user, an agent provider that mints identity assertions in the ID-JAG shape, and a service that accepts those assertions when available and issues the credentials.
How does auth.md register an agent that has no user identity?
It falls back to an RFC 8628-style claim ceremony. Anonymous registration returns an access token with pre-claim scopes, and ownership is claimed later at POST /agent/identity/claim with the claim token and an email address.
Which endpoints does the auth.md sample service expose for registration?
POST /agent/identity takes the chosen identity assertion and returns a service-signed identity_assertion, and POST /oauth2/token exchanges it under the RFC 7523 JWT-bearer grant for an access token. Discovery sits at /.well-known/oauth-authorization-server with an agent_auth block added to the standard metadata.
Is auth.md available as a published package or release?
The repository has no GitHub releases, and the root package.json is marked private at version 0.6.0, so that version is a workspace counter rather than an installable release. The root is a pnpm workspace pinned to [email protected].
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/workos-auth-md)