{"id":50707867,"url":"https://github.com/workos/auth.md","last_synced_at":"2026-06-20T12:34:26.433Z","repository":{"id":360366436,"uuid":"1244959261","full_name":"workos/auth.md","owner":"workos","description":"An open protocol that lets agents register for services on behalf of users — discoverable through a Markdown file at your domain.","archived":false,"fork":false,"pushed_at":"2026-06-10T18:12:45.000Z","size":290,"stargazers_count":415,"open_issues_count":7,"forks_count":35,"subscribers_count":6,"default_branch":"main","last_synced_at":"2026-06-10T18:14:20.311Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/workos.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-20T19:13:30.000Z","updated_at":"2026-06-10T16:55:52.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/workos/auth.md","commit_stats":null,"previous_names":["workos/auth.md"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/workos/auth.md","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/workos%2Fauth.md","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/workos%2Fauth.md/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/workos%2Fauth.md/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/workos%2Fauth.md/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/workos","download_url":"https://codeload.github.com/workos/auth.md/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/workos%2Fauth.md/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34570538,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-20T02:00:06.407Z","response_time":98,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-06-09T13:00:37.288Z","updated_at":"2026-06-20T12:34:26.420Z","avatar_url":"https://github.com/workos.png","language":"TypeScript","funding_links":[],"categories":["TypeScript"],"sub_categories":[],"readme":"# auth.md\n\nA reference implementation of **agentic registration** — a protocol for agents to authenticate to services on behalf of users. Three roles: an **agent** acting for a user, an **agent provider** that mints identity assertions ([ID-JAGs](https://datatracker.ietf.org/doc/draft-ietf-oauth-identity-assertion-authz-grant/)), and a **service** that accepts those assertions, when available, and issues credentials. If the agent is not associated with a user identity, or the agent provider does not support ID-JAGs, the service uses an [RFC 8628](https://datatracker.ietf.org/doc/html/rfc8628)-style claim ceremony to authenticate the agent instead.\n\nThis repo includes sample implementations for both the agent provider and agent service side of agentic registration, and includes a sample [`AUTH.md`](AUTH.md) file, which the agent service would host, instructing agents how to authenticate with the service.\n\n## Layout\n\n```\n.\n├── AUTH.md            ← skill manifest agents read\n├── agent-services/    ← sample resource server + authorization server\n├── agent-providers/   ← sample agent IdP that mints ID-JAGs\n└── shared/            ← shared workspace package (ports, types)\n```\n\n## Where to go next\n\n- **You're an agent or want an auth.md template** → [AUTH.md](AUTH.md) — procedural recipe (discover → register → claim → exchange → use → handle revoke).\n- **You're implementing a service** → [agent-services/README.md](agent-services/README.md) — full implementation guide, sequence diagrams, error tables.\n- **You're implementing an IdP** → [agent-providers/README.md](agent-providers/README.md) — minting ID-JAGs, publishing JWKS, sending revocation events.\n\n## Quickstart\n\n```sh\npnpm install\npnpm dev\n```\n\nService at \u003chttp://localhost:8000\u003e, provider at \u003chttp://localhost:4000\u003e. The service home page walks the three registration flows interactively. Use `pnpm dev:service` or `pnpm dev:provider` to run one side at a time.\n\n## System Flows\n\nRegistration and credential issuance are split across two endpoints. `POST /agent/identity` accepts the agent's chosen identity assertion (ID-JAG, verified email, or anonymous) and returns a service-signed `identity_assertion`. The agent then exchanges that assertion at `POST /oauth2/token` (RFC 7523 JWT-bearer grant) for an access_token.\n\n### Discovery\n\nHosted at `/.well-known/oauth-authorization-server`:\n\n```json\n{\n  \"resource\": \"https://api.service.example.com/\",\n  \"authorization_servers\": [\"https://auth.service.example.com/\"],\n  \"scopes_supported\": [\"api.read\", \"api.write\"],\n  \"bearer_methods_supported\": [\"header\"],\n\n  \"issuer\": \"https://auth.service.example.com\",\n  \"token_endpoint\": \"https://auth.service.example.com/oauth2/token\",\n  \"revocation_endpoint\": \"https://auth.service.example.com/oauth2/revoke\",\n  \"grant_types_supported\": [\n    \"urn:ietf:params:oauth:grant-type:jwt-bearer\",\n    \"urn:workos:agent-auth:grant-type:claim\"\n  ],\n\n  \"agent_auth\": {\n    \"skill\": \"https://service.example.com/auth.md\",\n    \"identity_endpoint\": \"https://auth.service.example.com/agent/identity\",\n    \"claim_endpoint\": \"https://auth.service.example.com/agent/identity/claim\",\n    \"events_endpoint\": \"https://auth.service.example.com/agent/event/notify\",\n    \"identity_types_supported\": [\"anonymous\", \"identity_assertion\", \"service_auth\"],\n    \"identity_assertion\": {\n      \"assertion_types_supported\": [\n        \"urn:ietf:params:oauth:token-type:id-jag\"\n      ]\n    },\n    \"events_supported\": [\n      \"https://schemas.workos.com/events/agent/auth/identity/assertion/revoked\"\n    ]\n  }\n}\n```\n\nThe top-level `issuer` / `token_endpoint` / `revocation_endpoint` / `grant_types_supported` are standard [RFC 8414](https://datatracker.ietf.org/doc/html/rfc8414) / [RFC 7009](https://datatracker.ietf.org/doc/html/rfc7009) / [RFC 7523](https://datatracker.ietf.org/doc/html/rfc7523) fields. The `agent_auth` block is the profile extension carrying the registration and claim surface.\n\n### Identity Assertion (ID-JAG)\n\n```mermaid\nsequenceDiagram\n    actor User\n    participant Agent\n    participant Provider as Agent Provider\n    participant Service\n\n    Agent-\u003e\u003eService: GET /api/resource\n    Service--\u003e\u003eAgent: 401 Unauthorized\u003cbr/\u003eWWW-Authenticate: Bearer resource_metadata=\"...\"\n\n    Agent-\u003e\u003eService: GET /.well-known/oauth-protected-resource\n    Service--\u003e\u003eAgent: 200 OK (PRM with authorization_servers)\n    Agent-\u003e\u003eService: GET /.well-known/oauth-authorization-server\n    Service--\u003e\u003eAgent: 200 OK (AS metadata with agent_auth block)\n\n    Agent-\u003e\u003eUser: Consent to assert identity to audience?\n    User--\u003e\u003eAgent: Consent granted\n\n    Agent-\u003e\u003eProvider: Request audience-specific ID-JAG\n    Provider--\u003e\u003eAgent: 200 OK (ID-JAG)\n\n    Agent-\u003e\u003eService: POST /agent/identity\u003cbr/\u003e{ type: identity_assertion, assertion: ID-JAG }\n    Service-\u003e\u003eProvider: GET /.well-known/jwks.json\n    Provider--\u003e\u003eService: 200 OK (JSON Web Key Set)\n    Service--\u003e\u003eAgent: 200 OK (identity_assertion)\n\n    Agent-\u003e\u003eService: POST /oauth2/token\u003cbr/\u003egrant_type=jwt-bearer\u0026assertion=...\n    Service--\u003e\u003eAgent: 200 OK (access_token)\n```\n\n### Verified-Email Identity Assertion\n\n```mermaid\nsequenceDiagram\n    actor User\n    participant Agent\n    participant Service\n\n    Agent-\u003e\u003eService: POST /agent/identity\u003cbr/\u003e{ type: service_auth, login_hint: email }\n    Service--\u003e\u003eAgent: 200 OK (claim_token, claim: user_code + verification_uri)\n    Agent--\u003e\u003eUser: Surface user_code + verification_uri\n    User-\u003e\u003eService: GET verification_uri (signs in, lands on /claim)\n    User-\u003e\u003eService: POST /agent/identity/claim/complete\u003cbr/\u003e{ claim_attempt_token, user_code }\n\n    loop until claimed\n      Agent-\u003e\u003eService: POST /oauth2/token\u003cbr/\u003egrant_type=claim\u0026claim_token=...\n      alt user_code window open\n        Service--\u003e\u003eAgent: 200 OK (access_token + identity_assertion) | authorization_pending\n      else user_code expired (outer claim window still open)\n        Service--\u003e\u003eAgent: 400 expired_token\n        Agent-\u003e\u003eService: POST /agent/identity/claim\u003cbr/\u003e{ claim_token, email }\n        Service--\u003e\u003eAgent: 200 OK (fresh claim_attempt: new user_code + verification_uri)\n        Agent--\u003e\u003eUser: Surface new user_code + verification_uri\n      end\n    end\n```\n\n### Anonymous Registration with Claim Ceremony\n\n```mermaid\nsequenceDiagram\n    actor User\n    participant Agent\n    participant Service\n\n    Agent-\u003e\u003eService: POST /agent/identity\u003cbr/\u003e{ type: anonymous }\n    Service--\u003e\u003eAgent: 200 OK (identity_assertion, claim_token)\n    Agent-\u003e\u003eService: POST /oauth2/token\u003cbr/\u003egrant_type=jwt-bearer\u0026assertion=...\n    Service--\u003e\u003eAgent: 200 OK (access_token with pre-claim scope)\n\n    Note over Agent: Agent operates with pre-claim scopes\n\n    User--\u003e\u003eAgent: Wants to take ownership\n    Agent-\u003e\u003eService: POST /agent/identity/claim\u003cbr/\u003e{ claim_token, email }\n    Service--\u003e\u003eAgent: 200 OK (claim_attempt: user_code + verification_uri)\n    Agent--\u003e\u003eUser: Surface user_code + verification_uri\n    User-\u003e\u003eService: GET verification_uri (signs in, lands on /claim)\n    User-\u003e\u003eService: POST /agent/identity/claim/complete\u003cbr/\u003e{ claim_attempt_token, user_code }\n\n    loop until claimed\n      Agent-\u003e\u003eService: POST /oauth2/token\u003cbr/\u003egrant_type=claim\u0026claim_token=...\n      alt user_code window open\n        Service--\u003e\u003eAgent: 200 OK (post-claim access_token + v2 identity_assertion) | authorization_pending\n      else user_code expired (outer claim window still open)\n        Service--\u003e\u003eAgent: 400 expired_token\n        Agent-\u003e\u003eService: POST /agent/identity/claim\u003cbr/\u003e{ claim_token, email }\n        Service--\u003e\u003eAgent: 200 OK (fresh claim_attempt: new user_code + verification_uri)\n        Agent--\u003e\u003eUser: Surface new user_code + verification_uri\n      end\n    end\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fworkos%2Fauth.md","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fworkos%2Fauth.md","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fworkos%2Fauth.md/lists"}