Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

workos/auth.md

Open more actions menu

Repository files navigation

auth.md

A 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), 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-style claim ceremony to authenticate the agent instead.

This repo includes sample implementations for both the agent provider and agent service side of agentic registration, and includes a sample AUTH.md file, which the agent service would host, instructing agents how to authenticate with the service.

Layout

.
├── 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)

Where to go next

  • You're an agent or want an auth.md templateAUTH.md — procedural recipe (discover → register → claim → exchange → use → handle revoke).
  • You're implementing a serviceagent-services/README.md — full implementation guide, sequence diagrams, error tables.
  • You're implementing an IdPagent-providers/README.md — minting ID-JAGs, publishing JWKS, sending revocation events.

Quickstart

pnpm install
pnpm dev

Service at http://localhost:8000, provider at http://localhost:4000. 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.

System Flows

Registration 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.

Discovery

Hosted at /.well-known/oauth-authorization-server:

{
  "resource": "https://api.service.example.com/",
  "authorization_servers": ["https://auth.service.example.com/"],
  "scopes_supported": ["api.read", "api.write"],
  "bearer_methods_supported": ["header"],

  "issuer": "https://auth.service.example.com",
  "token_endpoint": "https://auth.service.example.com/oauth2/token",
  "revocation_endpoint": "https://auth.service.example.com/oauth2/revoke",
  "grant_types_supported": [
    "urn:ietf:params:oauth:grant-type:jwt-bearer",
    "urn:workos:agent-auth:grant-type:claim"
  ],

  "agent_auth": {
    "skill": "https://service.example.com/auth.md",
    "identity_endpoint": "https://auth.service.example.com/agent/identity",
    "claim_endpoint": "https://auth.service.example.com/agent/identity/claim",
    "events_endpoint": "https://auth.service.example.com/agent/event/notify",
    "identity_types_supported": ["anonymous", "identity_assertion", "service_auth"],
    "identity_assertion": {
      "assertion_types_supported": [
        "urn:ietf:params:oauth:token-type:id-jag"
      ]
    },
    "events_supported": [
      "https://schemas.workos.com/events/agent/auth/identity/assertion/revoked"
    ]
  }
}

The top-level issuer / token_endpoint / revocation_endpoint / grant_types_supported are standard RFC 8414 / RFC 7009 / RFC 7523 fields. The agent_auth block is the profile extension carrying the registration and claim surface.

Identity Assertion (ID-JAG)

sequenceDiagram
    actor User
    participant Agent
    participant Provider as Agent Provider
    participant Service

    Agent->>Service: GET /api/resource
    Service-->>Agent: 401 Unauthorized<br/>WWW-Authenticate: Bearer resource_metadata="..."

    Agent->>Service: GET /.well-known/oauth-protected-resource
    Service-->>Agent: 200 OK (PRM with authorization_servers)
    Agent->>Service: GET /.well-known/oauth-authorization-server
    Service-->>Agent: 200 OK (AS metadata with agent_auth block)

    Agent->>User: Consent to assert identity to audience?
    User-->>Agent: Consent granted

    Agent->>Provider: Request audience-specific ID-JAG
    Provider-->>Agent: 200 OK (ID-JAG)

    Agent->>Service: POST /agent/identity<br/>{ type: identity_assertion, assertion: ID-JAG }
    Service->>Provider: GET /.well-known/jwks.json
    Provider-->>Service: 200 OK (JSON Web Key Set)
    Service-->>Agent: 200 OK (identity_assertion)

    Agent->>Service: POST /oauth2/token<br/>grant_type=jwt-bearer&assertion=...
    Service-->>Agent: 200 OK (access_token)
Loading

Verified-Email Identity Assertion

sequenceDiagram
    actor User
    participant Agent
    participant Service

    Agent->>Service: POST /agent/identity<br/>{ type: service_auth, login_hint: email }
    Service-->>Agent: 200 OK (claim_token, claim: user_code + verification_uri)
    Agent-->>User: Surface user_code + verification_uri
    User->>Service: GET verification_uri (signs in, lands on /claim)
    User->>Service: POST /agent/identity/claim/complete<br/>{ claim_attempt_token, user_code }

    loop until claimed
      Agent->>Service: POST /oauth2/token<br/>grant_type=claim&claim_token=...
      alt user_code window open
        Service-->>Agent: 200 OK (access_token + identity_assertion) | authorization_pending
      else user_code expired (outer claim window still open)
        Service-->>Agent: 400 expired_token
        Agent->>Service: POST /agent/identity/claim<br/>{ claim_token, email }
        Service-->>Agent: 200 OK (fresh claim_attempt: new user_code + verification_uri)
        Agent-->>User: Surface new user_code + verification_uri
      end
    end
Loading

Anonymous Registration with Claim Ceremony

sequenceDiagram
    actor User
    participant Agent
    participant Service

    Agent->>Service: POST /agent/identity<br/>{ type: anonymous }
    Service-->>Agent: 200 OK (identity_assertion, claim_token)
    Agent->>Service: POST /oauth2/token<br/>grant_type=jwt-bearer&assertion=...
    Service-->>Agent: 200 OK (access_token with pre-claim scope)

    Note over Agent: Agent operates with pre-claim scopes

    User-->>Agent: Wants to take ownership
    Agent->>Service: POST /agent/identity/claim<br/>{ claim_token, email }
    Service-->>Agent: 200 OK (claim_attempt: user_code + verification_uri)
    Agent-->>User: Surface user_code + verification_uri
    User->>Service: GET verification_uri (signs in, lands on /claim)
    User->>Service: POST /agent/identity/claim/complete<br/>{ claim_attempt_token, user_code }

    loop until claimed
      Agent->>Service: POST /oauth2/token<br/>grant_type=claim&claim_token=...
      alt user_code window open
        Service-->>Agent: 200 OK (post-claim access_token + v2 identity_assertion) | authorization_pending
      else user_code expired (outer claim window still open)
        Service-->>Agent: 400 expired_token
        Agent->>Service: POST /agent/identity/claim<br/>{ claim_token, email }
        Service-->>Agent: 200 OK (fresh claim_attempt: new user_code + verification_uri)
        Agent-->>User: Surface new user_code + verification_uri
      end
    end
Loading

About

An open protocol that lets agents register for services on behalf of users — discoverable through a Markdown file at your domain.

Resources

Stars

Watchers

Forks

Releases

Packages

Used by

Contributors

Languages

Morty Proxy This is a proxified and sanitized view of the page, visit original site.