auth-md
Generate, validate, and explain the auth.md protocol — the open standard that lets AI agents register for services on behalf of users, without signup forms.
Protocol Context
auth.md is a Markdown file published at a service's root (typically https://service.com/auth.md) that instructs agents on how to register. It works simultaneously as human-readable documentation and as a discoverable runtime artifact for agents.
The protocol extends RFC 9728 (OAuth 2.0 Protected Resource Metadata) with an agent_auth block in the Authorization Server metadata. Registration returns an identity_assertion (service-signed JWT) that the agent exchanges at /oauth2/token for an access_token. Three registration methods are supported:
| Flow | Mechanism | When to use |
|---|---|---|
| identity_assertion | Provider signs an ID-JAG (with auth_time) asserting user identity. Service verifies JWKS, returns identity_assertion. Agent exchanges at /oauth2/token. | Service does JIT provisioning from OIDC/SAML; wants zero-friction registration. |
| service_auth | Email hint + browser-based ceremony. Agent receives user_code + verification_uri; user signs in and types code. Agent polls /oauth2/token. | Agents on platforms that can't mint ID-JAGs; self-serve without trust list. |
| anonymous | No identity upfront. Immediate identity_assertion with pre-claim scopes. Optional deferred claim for scope upgrade. | Agent needs basic access immediately; human ownership binding deferred. |
Protocol Endpoints
| Endpoint | Purpose |
|---|---|
/.well-known/oauth-protected-resource | Discovery — resource metadata (RFC 9728) |
/.well-known/oauth-authorization-server | Discovery — AS metadata with agent_auth block |
POST /agent/identity | Registration — dispatches on type field |
POST /agent/identity/claim | Claim initiation (anonymous deferred, or re-initiate expired user_code) |
POST /oauth2/token | Token exchange (JWT-bearer grant) + claim polling (claim grant) |
POST /oauth2/revoke | Credential-layer revocation (RFC 7009) |
events_endpoint | Registration-layer revocation (receives SETs, RFC 8935) |
Token Lifecycle
Registration never returns an access_token directly. The flow is:
- Registration →
identity_assertion(service-signed JWT, reusable until expiry) - Exchange →
POST /oauth2/tokenwithgrant_type=urn:ietf:params:oauth:grant-type:jwt-bearer→access_token - Refresh → re-exchange same
identity_assertionwhen access_token expires - Expired assertion → restart at registration (Step 3)
Claim Ceremony (v2 — Browser-Based)
The claim ceremony uses RFC 8628-style device authorization:
- Registration returns
user_code+verification_uriin aclaimblock - Agent surfaces both to the user
- User opens
verification_uri, signs in to the service, types the 6-digit code - Agent polls
POST /oauth2/tokenwithgrant_type=urn:workos:agent-auth:grant-type:claim+claim_token - On success: receives
access_token+ freshidentity_assertion
Operation Modes
| Parameter | Default | Description |
|---|---|---|
mode | generate | generate = create auth.md + metadata; validate = check existing auth.md; explain = explain the protocol |
validation_level | basic | basic = structure + fields + consistency (offline); full = basic + live endpoint fetch |
flows | all | Which flows to include: identity_assertion, service_auth, anonymous, all |
role | app | Perspective: app = service accepting registrations; provider = platform minting ID-JAGs |
Workflow: Generate
1. Scan the codebase
Look for:
- Existing API routes and authentication patterns
- Defined scopes/permissions
- Framework (Express, Django, Rails, FastAPI, NestJS, etc.)
- Base URL and auth server URL configuration
- Existing authentication middleware
- User models and provisioning mechanisms
2. Ask the user only what cannot be inferred
- Which flows to support (identity_assertion, service_auth, anonymous, or combination)
- Pre-claim scopes vs post-claim scopes (if anonymous)
- Trusted agent providers and trust list policy (if identity_assertion)
- Whether the service already does JIT provisioning or requires manual onboarding
idJagMaxAuthAgeSecondsvalue (default: 3600)- Desired rate limiting policy
3. Generate artifacts
Produce three artifacts:
a) auth.md — Markdown file following the protocol template (see references/protocol-template.md). Must contain:
- Title and intro addressed to the agent
- Step 1 — Discover (two hops: PRM → AS metadata)
- Step 2 — Pick a method (decision tree)
- Step 3 — Register (one subsection per supported method)
- Step 4 — Claim ceremony (if service_auth or anonymous with claim)
- Step 5 — Exchange the assertion (POST /oauth2/token with jwt-bearer grant)
- Step 6 — Use the access_token
- Errors (complete table with all applicable codes)
- Revocation (two layers)
b) oauth-protected-resource.json — JSON for /.well-known/oauth-protected-resource with resource_name and resource_logo_uri
c) oauth-authorization-server.json — JSON for /.well-known/oauth-authorization-server with:
issuer,token_endpoint,revocation_endpoint,grant_types_supported- Complete
agent_authblock withidentity_endpoint,claim_endpoint,events_endpoint
4. Generate implementation guidance
"Next Steps" section with:
- How to serve
auth.mdat the domain root - How to serve metadata at the well-known paths
- How to add
WWW-Authenticateheader to 401 responses - Endpoint implementation guidance (without generating framework-specific code unless requested)
- Token exchange implementation at
/oauth2/token - Claim page hosting (verification_uri → login → code input → confirm)
- Recommended rate limiting configuration
- Recommended audit events
- Security considerations (token hashing, auth_time validation, replay protection, claim_token handling)
5. Generate Agent Provider guide (if role=provider)
When the user is an agent provider (not an app), generate:
- How to mint audience-specific ID-JAGs with
auth_time - Token structure (header + payload with required and optional claims)
- How to publish JWKS
- Optionally: how to publish a CIMD (Client ID Metadata Document)
- How to implement revocation (POST SET to events_endpoint)
- How to present consent to the user before asserting identity (using
resource_name+resource_logo_uri)
Workflow: Validate
1. Load the auth.md
From a local file path or URL.
2. Run validation at the requested level
Basic (offline):
- All required headings present (Step 1–6, Errors, Revocation)
- At least one flow documented
- Valid JSON in fenced code blocks for request/response shapes
- AS metadata contains
identity_endpoint,token_endpoint,grant_types_supported - Error table with standard error codes
- Consistency: flows in prose match
identity_types_supportedin metadata JSON - No unreplaced placeholders
Full (live):
- All basic checks, plus:
- Fetch
/.well-known/oauth-protected-resourcefrom the declared base URL - Verify
agent_authblock exists in AS metadata - Fetch
/.well-known/oauth-authorization-serverand verify consistency - Check that
identity_endpoint,token_endpoint,revocation_endpointrespond (accept 400/401/422, reject 404/405) - Verify API returns 401 with
WWW-Authenticatecontainingresource_metadata
3. Report results
Checklist with ✅/❌ per rule, grouped by category:
- Structure — headings and order
- Fields — required fields in JSONs
- Consistency — cross-references between prose and metadata
- Format — valid JSON, valid HTTP, no placeholders
- Endpoints (full only) — reachability and correct responses
Include severity: 🔴 Error (agents will fail), 🟡 Warning (degraded experience), 🟢 Info (suggestion).
See references/validation-rules.md for the complete ruleset.
Workflow: Explain
When the user wants to understand the protocol without generating or validating:
- Identify what the user wants to know (overview, specific flow, specific endpoint, security, etc.)
- Explain using the protocol context above and the references
- Use text-based sequence diagrams when helpful
- Point to official documentation when relevant
User Matching and JIT Provisioning
The identity_assertion flow needs to decide which service user a registration represents. Recommended resolution order:
- Delegation record match — if
(iss, sub)has a delegation on file, route to same user - Verified email match — if a user exists with same verified email BUT no
(iss, sub)delegation →interaction_required(401) with claim block for user to confirm linking - Verified phone match — same pattern
- No match → JIT — create a new user per provisioning policy, or refuse
Reject ID-JAGs with neither a verified email nor a verified phone — there's no basis for matching.
Rate Limiting
The /agent/identity endpoint is unauthenticated for anonymous registration. Implement two tiers:
- Per-IP (checked first) — prevents a single source from consuming the tenant's budget. Default: 5/hour anonymous, 60/hour identity_assertion.
- Per-tenant (checked second) — global cap across IPs. Default: 100/hour anonymous, 1000/hour identity_assertion.
Also rate-limit /oauth2/token polling — enforce interval from the claim block, reject with slow_down if too fast.
Recommended Audit Events
| Event | When | Data |
|---|---|---|
registration.created | Successful POST /agent/identity | registration_id, registration_type, iss, sub |
registration.interaction_required | 401 interaction_required | registration_id, iss, sub, matched_user_id |
registration.login_required | 401 login_required | iss, sub, auth_time, max_age |
claim.initiated | /agent/identity/claim called | registration_id, email |
claim.completed | User submitted correct user_code | registration_id, claimed_by_user_id |
claim.expired | user_code window or registration expired | registration_id |
token.exchanged | /oauth2/token jwt-bearer success | registration_id, access_token_id |
token.revoked | /oauth2/revoke called | access_token_id |
registration.revoked | SET processed at events_endpoint | registration_id, iss, sub |
Security Considerations
- auth_time validation —
auth_timeis required in ID-JAGs. Service validates againstidJagMaxAuthAgeSeconds. If too old, returnslogin_required(401) — agent must get user to re-authenticate at provider. - claim_token handling — returned exactly once in the registration response. Agent holds in memory only for ceremony duration. Do not persist past Step 4.
- Token hashing —
claim_tokenis a bearer secret. Store only SHA-256 hash server-side. - Consent UX — surface
resource_nameandresource_logo_urifrom PRM to the user before asserting identity. This is the user's only consent gate. - Two revocation layers — credential layer (agent-callable,
/oauth2/revoke, kills one access_token) vs registration layer (provider-driven SETs atevents_endpoint, kills identity_assertion + all derived tokens). - Replay protection — cache
jtivalues with TTL of at leastexp - iat+ clock skew (typically 6 min). - CIMD resolution — if
client_idis a URL, fetch as Client ID Metadata Document and verifyjwks_uri. - Bulk revocation — provide operator-facing mechanism to revoke all outstanding identity_assertions for a tenant.
Error Codes Reference
| Code | Where | Meaning |
|---|---|---|
anonymous_not_enabled | /agent/identity | Service doesn't accept anonymous |
service_auth_not_enabled | /agent/identity | service_auth disabled |
issuer_not_enabled | /agent/identity | Provider not on trust list |
invalid_request | /agent/identity | Body/claim/signature/jti/aud problems |
interaction_required (401) | /agent/identity | ID-JAG matched account, no delegation — claim needed |
login_required (401) | /agent/identity | auth_time too old — re-authenticate at provider |
invalid_claim_token | /agent/identity/claim | Token wrong or expired |
claimed_or_in_flight | /agent/identity/claim | Already claimed or wrong endpoint |
claim_expired | /agent/identity/claim | Registration expired |
invalid_grant | /oauth2/token | Assertion expired/revoked |
invalid_client | /oauth2/token | client_id not recognized |
unsupported_grant_type | /oauth2/token | Not jwt-bearer or claim grant |
authorization_pending | /oauth2/token (claim) | User hasn't completed ceremony |
expired_token | /oauth2/token (claim) | user_code window closed |
slow_down | /oauth2/token (claim) | Polling too fast |
rate_limited (429) | any | Back off and retry |
Agent Readiness Scanner Check
The isitagentready.com scanner validates auth.md as the authMd check. Pass criteria:
/auth.mdserved from site root with HTTP 200- Content is Markdown with H1 heading containing "auth.md"
- Optionally validates OAuth Protected Resource Metadata at
/.well-known/oauth-protected-resource - Optionally validates Authorization Server metadata at
/.well-known/oauth-authorization-server
To pass the check minimally:
markdown# auth.md This service accepts AI agent registrations. ## Authentication Agents can register via POST /agent/identity with a valid ID-JAG. See below for supported methods.
To pass with full marks (all metadata):
- Serve
/auth.mdwith proper heading - Publish
/.well-known/oauth-protected-resourcewithresource,resource_name,resource_logo_uri,authorization_servers,scopes_supported,bearer_methods_supported: ["header"] - Publish
/.well-known/oauth-authorization-serverwithissuer,token_endpoint,revocation_endpoint,grant_types_supported, andagent_authblock containingskill,identity_endpoint,claim_endpoint,events_endpoint, and registration methods
Scan command:
bashcurl -s -X POST 'https://isitagentready.com/api/scan' \ -H 'Content-Type: application/json' \ -d '{"url":"https://YOUR-DOMAIN/","enabledChecks":["authMd"]}' | jq '.checks.discovery.authMd'
Quality Checklist
Before delivering output, verify:
- Generated
auth.mdcontains all required steps (1-6) + Errors + Revocation - AS metadata includes
issuer,token_endpoint,revocation_endpoint,grant_types_supported -
agent_authblock includesidentity_endpoint,claim_endpoint,events_endpoint -
identity_types_supportedmatches the flows the user chose -
scopes_supportedreflects actual API scopes found in codebase - Base URLs are consistent between auth.md and metadata JSON
- Error codes table includes all standard codes for the supported flows
- Step 5 documents token exchange at
/oauth2/tokenwith jwt-bearer grant - Revocation section documents both layers (credential + registration)
- No unreplaced placeholder values (
{{...}},<your-...>,[YOUR_...]) - Validation report covers all rules for the requested level
- Rate limiting documented (including /oauth2/token polling)
- Security considerations included (auth_time, claim_token, consent UX)
- If role=provider: ID-JAG structure with
auth_timedocumented
References
references/protocol-template.md— Complete auth.md template with all sections and placeholdersreferences/validation-rules.md— Full validation ruleset with error messages and severitiesreferences/metadata-schema.md— JSON schema for PRM, AS metadata, ID-JAG, and identity_assertionreferences/example-auth-md.md— Working example of a complete auth.md file (Acme Notes)references/implementation-guide.md— Server-side implementation guide with token exchange, claim ceremony, revocation, and security
Updating Protocol Knowledge
This skill ships with a snapshot of the auth.md protocol specification (v2, June 2026). When possible, fetch the latest version from:
- Skill Home and Doc Hub:
https://auth-md.com - Spec:
https://raw.githubusercontent.com/workos/auth.md/refs/heads/main/AUTH.md - Docs overview:
https://workos.com/auth-md/docs - Apps guide:
https://workos.com/auth-md/docs/apps - Agent providers guide:
https://workos.com/auth-md/docs/agent-providers - File anatomy:
https://workos.com/auth-md/docs/auth-md
If fetch fails, use the bundled references/ as the source of truth.

