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/token with grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer → access_token
- Refresh → re-exchange same
identity_assertion when 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_uri in a claim block
- Agent surfaces both to the user
- User opens
verification_uri, signs in to the service, types the 6-digit code
- Agent polls
POST /oauth2/token with grant_type=urn:workos:agent-auth:grant-type:claim + claim_token
- On success: receives
access_token + fresh identity_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
idJagMaxAuthAgeSeconds value (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_auth block with identity_endpoint, claim_endpoint, events_endpoint
4. Generate implementation guidance
"Next Steps" section with:
- How to serve
auth.md at the domain root
- How to serve metadata at the well-known paths
- How to add
WWW-Authenticate header 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_supported in metadata JSON
- No unreplaced placeholders
Full (live):
- All basic checks, plus:
- Fetch
/.well-known/oauth-protected-resource from the declared base URL
- Verify
agent_auth block exists in AS metadata
- Fetch
/.well-known/oauth-authorization-server and verify consistency
- Check that
identity_endpoint, token_endpoint, revocation_endpoint respond (accept 400/401/422, reject 404/405)
- Verify API returns 401 with
WWW-Authenticate containing resource_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_time is required in ID-JAGs. Service validates against idJagMaxAuthAgeSeconds. If too old, returns login_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_token is a bearer secret. Store only SHA-256 hash server-side.
- Consent UX — surface
resource_name and resource_logo_uri from 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 at events_endpoint, kills identity_assertion + all derived tokens).
- Replay protection — cache
jti values with TTL of at least exp - iat + clock skew (typically 6 min).
- CIMD resolution — if
client_id is a URL, fetch as Client ID Metadata Document and verify jwks_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.md served 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:
# 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.md with proper heading
- Publish
/.well-known/oauth-protected-resource with resource, resource_name, resource_logo_uri, authorization_servers, scopes_supported, bearer_methods_supported: ["header"]
- Publish
/.well-known/oauth-authorization-server with issuer, token_endpoint, revocation_endpoint, grant_types_supported, and agent_auth block containing skill, identity_endpoint, claim_endpoint, events_endpoint, and registration methods
Scan command:
curl -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:
References
references/protocol-template.md — Complete auth.md template with all sections and placeholders
references/validation-rules.md — Full validation ruleset with error messages and severities
references/metadata-schema.md — JSON schema for PRM, AS metadata, ID-JAG, and identity_assertion
references/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.
1---2name: auth-md3description: Generate, validate, and explain `auth.md` files — the open protocol for AI agent registration. Use when making apps agent-ready, generating Protected Resource Metadata (RFC 9728), validating auth.md files, or implementing agent registration endpoints. Triggers on "auth.md", "agent registration", "agent auth", "make my app agent-ready", "ID-JAG", "identity_assertion", "service_auth", "protected resource metadata", "agentic registration".4---56# auth-md78Generate, validate, and explain the **auth.md** protocol — the open standard that lets AI agents register for services on behalf of users, without signup forms.910---1112## Protocol Context1314auth.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.1516The 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:1718| Flow | Mechanism | When to use |19|------|-----------|-------------|20| **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. |21| **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. |22| **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. |2324### Protocol Endpoints2526| Endpoint | Purpose |27|----------|---------|28| `/.well-known/oauth-protected-resource` | Discovery — resource metadata (RFC 9728) |29| `/.well-known/oauth-authorization-server` | Discovery — AS metadata with `agent_auth` block |30| `POST /agent/identity` | Registration — dispatches on `type` field |31| `POST /agent/identity/claim` | Claim initiation (anonymous deferred, or re-initiate expired user_code) |32| `POST /oauth2/token` | Token exchange (JWT-bearer grant) + claim polling (claim grant) |33| `POST /oauth2/revoke` | Credential-layer revocation (RFC 7009) |34| `events_endpoint` | Registration-layer revocation (receives SETs, RFC 8935) |3536### Token Lifecycle3738Registration **never** returns an `access_token` directly. The flow is:39401. Registration → `identity_assertion` (service-signed JWT, reusable until expiry)412. Exchange → `POST /oauth2/token` with `grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer` → `access_token`423. Refresh → re-exchange same `identity_assertion` when access_token expires434. Expired assertion → restart at registration (Step 3)4445### Claim Ceremony (v2 — Browser-Based)4647The claim ceremony uses RFC 8628-style device authorization:481. Registration returns `user_code` + `verification_uri` in a `claim` block492. Agent surfaces both to the user503. User opens `verification_uri`, signs in to the service, types the 6-digit code514. Agent polls `POST /oauth2/token` with `grant_type=urn:workos:agent-auth:grant-type:claim` + `claim_token`525. On success: receives `access_token` + fresh `identity_assertion`5354---5556## Operation Modes5758| Parameter | Default | Description |59|-----------|---------|-------------|60| `mode` | `generate` | `generate` = create auth.md + metadata; `validate` = check existing auth.md; `explain` = explain the protocol |61| `validation_level` | `basic` | `basic` = structure + fields + consistency (offline); `full` = basic + live endpoint fetch |62| `flows` | `all` | Which flows to include: `identity_assertion`, `service_auth`, `anonymous`, `all` |63| `role` | `app` | Perspective: `app` = service accepting registrations; `provider` = platform minting ID-JAGs |6465---6667## Workflow: Generate6869### 1. Scan the codebase7071Look for:72- Existing API routes and authentication patterns73- Defined scopes/permissions74- Framework (Express, Django, Rails, FastAPI, NestJS, etc.)75- Base URL and auth server URL configuration76- Existing authentication middleware77- User models and provisioning mechanisms7879### 2. Ask the user only what cannot be inferred8081- Which flows to support (identity_assertion, service_auth, anonymous, or combination)82- Pre-claim scopes vs post-claim scopes (if anonymous)83- Trusted agent providers and trust list policy (if identity_assertion)84- Whether the service already does JIT provisioning or requires manual onboarding85- `idJagMaxAuthAgeSeconds` value (default: 3600)86- Desired rate limiting policy8788### 3. Generate artifacts8990Produce three artifacts:9192**a) `auth.md`** — Markdown file following the protocol template (see `references/protocol-template.md`). Must contain:93- Title and intro addressed to the agent94- Step 1 — Discover (two hops: PRM → AS metadata)95- Step 2 — Pick a method (decision tree)96- Step 3 — Register (one subsection per supported method)97- Step 4 — Claim ceremony (if service_auth or anonymous with claim)98- Step 5 — Exchange the assertion (POST /oauth2/token with jwt-bearer grant)99- Step 6 — Use the access_token100- Errors (complete table with all applicable codes)101- Revocation (two layers)102103**b) `oauth-protected-resource.json`** — JSON for `/.well-known/oauth-protected-resource` with `resource_name` and `resource_logo_uri`104105**c) `oauth-authorization-server.json`** — JSON for `/.well-known/oauth-authorization-server` with:106- `issuer`, `token_endpoint`, `revocation_endpoint`, `grant_types_supported`107- Complete `agent_auth` block with `identity_endpoint`, `claim_endpoint`, `events_endpoint`108109### 4. Generate implementation guidance110111"Next Steps" section with:112- How to serve `auth.md` at the domain root113- How to serve metadata at the well-known paths114- How to add `WWW-Authenticate` header to 401 responses115- Endpoint implementation guidance (without generating framework-specific code unless requested)116- Token exchange implementation at `/oauth2/token`117- Claim page hosting (verification_uri → login → code input → confirm)118- Recommended rate limiting configuration119- Recommended audit events120- Security considerations (token hashing, auth_time validation, replay protection, claim_token handling)121122### 5. Generate Agent Provider guide (if role=provider)123124When the user is an agent provider (not an app), generate:125- How to mint audience-specific ID-JAGs with `auth_time`126- Token structure (header + payload with required and optional claims)127- How to publish JWKS128- Optionally: how to publish a CIMD (Client ID Metadata Document)129- How to implement revocation (POST SET to events_endpoint)130- How to present consent to the user before asserting identity (using `resource_name` + `resource_logo_uri`)131132---133134## Workflow: Validate135136### 1. Load the auth.md137138From a local file path or URL.139140### 2. Run validation at the requested level141142**Basic (offline):**143- All required headings present (Step 1–6, Errors, Revocation)144- At least one flow documented145- Valid JSON in fenced code blocks for request/response shapes146- AS metadata contains `identity_endpoint`, `token_endpoint`, `grant_types_supported`147- Error table with standard error codes148- Consistency: flows in prose match `identity_types_supported` in metadata JSON149- No unreplaced placeholders150151**Full (live):**152- All basic checks, plus:153- Fetch `/.well-known/oauth-protected-resource` from the declared base URL154- Verify `agent_auth` block exists in AS metadata155- Fetch `/.well-known/oauth-authorization-server` and verify consistency156- Check that `identity_endpoint`, `token_endpoint`, `revocation_endpoint` respond (accept 400/401/422, reject 404/405)157- Verify API returns 401 with `WWW-Authenticate` containing `resource_metadata`158159### 3. Report results160161Checklist with ✅/❌ per rule, grouped by category:162- **Structure** — headings and order163- **Fields** — required fields in JSONs164- **Consistency** — cross-references between prose and metadata165- **Format** — valid JSON, valid HTTP, no placeholders166- **Endpoints** (full only) — reachability and correct responses167168Include severity: 🔴 Error (agents will fail), 🟡 Warning (degraded experience), 🟢 Info (suggestion).169170See `references/validation-rules.md` for the complete ruleset.171172---173174## Workflow: Explain175176When the user wants to understand the protocol without generating or validating:1771781. Identify what the user wants to know (overview, specific flow, specific endpoint, security, etc.)1792. Explain using the protocol context above and the references1803. Use text-based sequence diagrams when helpful1814. Point to official documentation when relevant182183---184185## User Matching and JIT Provisioning186187The identity_assertion flow needs to decide which service user a registration represents. Recommended resolution order:1881891. **Delegation record match** — if `(iss, sub)` has a delegation on file, route to same user1902. **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 linking1913. **Verified phone match** — same pattern1924. **No match → JIT** — create a new user per provisioning policy, or refuse193194Reject ID-JAGs with neither a verified email nor a verified phone — there's no basis for matching.195196---197198## Rate Limiting199200The `/agent/identity` endpoint is unauthenticated for anonymous registration. Implement two tiers:2012021. **Per-IP** (checked first) — prevents a single source from consuming the tenant's budget. Default: 5/hour anonymous, 60/hour identity_assertion.2032. **Per-tenant** (checked second) — global cap across IPs. Default: 100/hour anonymous, 1000/hour identity_assertion.204205Also rate-limit `/oauth2/token` polling — enforce `interval` from the claim block, reject with `slow_down` if too fast.206207---208209## Recommended Audit Events210211| Event | When | Data |212|-------|------|------|213| `registration.created` | Successful POST /agent/identity | registration_id, registration_type, iss, sub |214| `registration.interaction_required` | 401 interaction_required | registration_id, iss, sub, matched_user_id |215| `registration.login_required` | 401 login_required | iss, sub, auth_time, max_age |216| `claim.initiated` | /agent/identity/claim called | registration_id, email |217| `claim.completed` | User submitted correct user_code | registration_id, claimed_by_user_id |218| `claim.expired` | user_code window or registration expired | registration_id |219| `token.exchanged` | /oauth2/token jwt-bearer success | registration_id, access_token_id |220| `token.revoked` | /oauth2/revoke called | access_token_id |221| `registration.revoked` | SET processed at events_endpoint | registration_id, iss, sub |222223---224225## Security Considerations226227- **auth_time validation** — `auth_time` is required in ID-JAGs. Service validates against `idJagMaxAuthAgeSeconds`. If too old, returns `login_required` (401) — agent must get user to re-authenticate at provider.228- **claim_token handling** — returned exactly once in the registration response. Agent holds in memory only for ceremony duration. Do not persist past Step 4.229- **Token hashing** — `claim_token` is a bearer secret. Store only SHA-256 hash server-side.230- **Consent UX** — surface `resource_name` and `resource_logo_uri` from PRM to the user before asserting identity. This is the user's only consent gate.231- **Two revocation layers** — credential layer (agent-callable, `/oauth2/revoke`, kills one access_token) vs registration layer (provider-driven SETs at `events_endpoint`, kills identity_assertion + all derived tokens).232- **Replay protection** — cache `jti` values with TTL of at least `exp - iat` + clock skew (typically 6 min).233- **CIMD resolution** — if `client_id` is a URL, fetch as Client ID Metadata Document and verify `jwks_uri`.234- **Bulk revocation** — provide operator-facing mechanism to revoke all outstanding identity_assertions for a tenant.235236---237238## Error Codes Reference239240| Code | Where | Meaning |241|------|-------|---------|242| `anonymous_not_enabled` | `/agent/identity` | Service doesn't accept anonymous |243| `service_auth_not_enabled` | `/agent/identity` | service_auth disabled |244| `issuer_not_enabled` | `/agent/identity` | Provider not on trust list |245| `invalid_request` | `/agent/identity` | Body/claim/signature/jti/aud problems |246| `interaction_required` (401) | `/agent/identity` | ID-JAG matched account, no delegation — claim needed |247| `login_required` (401) | `/agent/identity` | auth_time too old — re-authenticate at provider |248| `invalid_claim_token` | `/agent/identity/claim` | Token wrong or expired |249| `claimed_or_in_flight` | `/agent/identity/claim` | Already claimed or wrong endpoint |250| `claim_expired` | `/agent/identity/claim` | Registration expired |251| `invalid_grant` | `/oauth2/token` | Assertion expired/revoked |252| `invalid_client` | `/oauth2/token` | client_id not recognized |253| `unsupported_grant_type` | `/oauth2/token` | Not jwt-bearer or claim grant |254| `authorization_pending` | `/oauth2/token` (claim) | User hasn't completed ceremony |255| `expired_token` | `/oauth2/token` (claim) | user_code window closed |256| `slow_down` | `/oauth2/token` (claim) | Polling too fast |257| `rate_limited` (429) | any | Back off and retry |258259---260261## Agent Readiness Scanner Check262263The [isitagentready.com](https://isitagentready.com) scanner validates auth.md as the `authMd` check. Pass criteria:2642651. `/auth.md` served from site root with HTTP 2002662. Content is Markdown with H1 heading containing "auth.md"2673. Optionally validates OAuth Protected Resource Metadata at `/.well-known/oauth-protected-resource`2684. Optionally validates Authorization Server metadata at `/.well-known/oauth-authorization-server`269270**To pass the check minimally:**271```markdown272# auth.md273274This service accepts AI agent registrations.275276## Authentication277278Agents can register via POST /agent/identity with a valid ID-JAG.279See below for supported methods.280```281282**To pass with full marks (all metadata):**283- Serve `/auth.md` with proper heading284- Publish `/.well-known/oauth-protected-resource` with `resource`, `resource_name`, `resource_logo_uri`, `authorization_servers`, `scopes_supported`, `bearer_methods_supported: ["header"]`285- Publish `/.well-known/oauth-authorization-server` with `issuer`, `token_endpoint`, `revocation_endpoint`, `grant_types_supported`, and `agent_auth` block containing `skill`, `identity_endpoint`, `claim_endpoint`, `events_endpoint`, and registration methods286287**Scan command:**288```bash289curl -s -X POST 'https://isitagentready.com/api/scan' \290 -H 'Content-Type: application/json' \291 -d '{"url":"https://YOUR-DOMAIN/","enabledChecks":["authMd"]}' | jq '.checks.discovery.authMd'292```293294---295296## Quality Checklist297298Before delivering output, verify:299300- [ ] Generated `auth.md` contains all required steps (1-6) + Errors + Revocation301- [ ] AS metadata includes `issuer`, `token_endpoint`, `revocation_endpoint`, `grant_types_supported`302- [ ] `agent_auth` block includes `identity_endpoint`, `claim_endpoint`, `events_endpoint`303- [ ] `identity_types_supported` matches the flows the user chose304- [ ] `scopes_supported` reflects actual API scopes found in codebase305- [ ] Base URLs are consistent between auth.md and metadata JSON306- [ ] Error codes table includes all standard codes for the supported flows307- [ ] Step 5 documents token exchange at `/oauth2/token` with jwt-bearer grant308- [ ] Revocation section documents both layers (credential + registration)309- [ ] No unreplaced placeholder values (`{{...}}`, `<your-...>`, `[YOUR_...]`)310- [ ] Validation report covers all rules for the requested level311- [ ] Rate limiting documented (including /oauth2/token polling)312- [ ] Security considerations included (auth_time, claim_token, consent UX)313- [ ] If role=provider: ID-JAG structure with `auth_time` documented314315---316317## References318319- `references/protocol-template.md` — Complete auth.md template with all sections and placeholders320- `references/validation-rules.md` — Full validation ruleset with error messages and severities321- `references/metadata-schema.md` — JSON schema for PRM, AS metadata, ID-JAG, and identity_assertion322- `references/example-auth-md.md` — Working example of a complete auth.md file (Acme Notes)323- `references/implementation-guide.md` — Server-side implementation guide with token exchange, claim ceremony, revocation, and security324325---326327## Updating Protocol Knowledge328329This skill ships with a snapshot of the auth.md protocol specification (v2, June 2026). When possible, fetch the latest version from:330331- Skill Home and Doc Hub: `https://auth-md.com`332- Spec: `https://raw.githubusercontent.com/workos/auth.md/refs/heads/main/AUTH.md`333- Docs overview: `https://workos.com/auth-md/docs`334- Apps guide: `https://workos.com/auth-md/docs/apps`335- Agent providers guide: `https://workos.com/auth-md/docs/agent-providers`336- File anatomy: `https://workos.com/auth-md/docs/auth-md`337338If fetch fails, use the bundled `references/` as the source of truth.