๐Ÿพ dummy-petshop โ€” a fake third party for integrations & secrets e2e (apps/os/docs/integrations-and-secrets-design.md ยง7 S0) GET /.well-known/oauth-protected-resource[/mcp] RFC 9728 โ€” /mcp's resource + this origin as its auth server GET /.well-known/oauth-authorization-server RFC 8414 โ€” authorize/token/register endpoints, PKCE S256, auth methods none + client_secret_basic POST /oauth/register RFC 7591 dynamic client registration โ†’ a client pinned to its redirect_uris; token_endpoint_auth_method "none" โ‡’ public (no secret, PKCE), else confidential GET /oauth/authorize ?client_id&redirect_uri&state[&code_challenge] โ€” consent page; add &approve=1[&user=x] to skip it (test lane); a DCR client's redirect_uri must be one it registered POST /oauth/authorize consent form submit โ†’ 302 redirect_uri?code=โ€ฆ&state=โ€ฆ POST /oauth/token grant_type=authorization_code | refresh_token; confidential = HTTP Basic (RFC 6749 ยง2.3.1), public = client_id in the body; PKCE code_verifier required for public clients (and any code that carried a challenge, RFC 7636) POST /api/legacy-login {email, password} โ†’ {accessToken, expiresInSeconds}; any email, password "correct-horse" POST /graphql GraphQL session-login door: NewSession (any username, password "correct-horse") โ†’ sealed ~3s session token, valid as an ordinary bearer on /api/* (one more way into the ONE pets API); expired/revoked โ†’ 401; no refresh grant โ€” re-login is the refresh GET /api/me bearer whoami: {sub, clientId, tokenExpiresInSeconds}; +{installationId, appId} for an installation token GET /api/pets the account's (entirely fictional) pets POST /app/installations//access_tokens GitHub-App installation token โ€” Authorization: Bearer (RS256 over header.payload, iss=appId, exp future) โ†’ {token, expires_at}; token works as a bearer on /api/* GET /openapi.json OpenAPI 3.1 doc for the typed pets API (listPets/getPet/createPet) POST /rpc/* oRPC handler for the pets API (what an @orpc/client talks); bearer-protected GET|POST /api/v2/* the same pets procedures served REST-shaped (per the OpenAPI doc) GET|POST /mcp MCP server (streamable HTTP): tools list_pets, get_pet, create_pet; bearer-protected โ€” an unauthorized call answers 401 + WWW-Authenticate pointing at the RFC 9728 metadata above (OAuth-protected MCP server) GET /gateway (websocket) โ€” token in the first {op:identify, token} FRAME (Discord shape) GET /gateway-header (websocket) โ€” token in the Authorization: Bearer UPGRADE header (OpenAI-Realtime shape) GET /gateway-subprotocol (websocket) โ€” token in Sec-WebSocket-Protocol as "petshop.access-token." (browser-WS shape) GET /__backdoor/state the whole mutable state, for spec assertions POST /__backdoor/clients {accessTokenTtlSeconds?} โ†’ mint {clientId, clientSecret} POST /__backdoor/expire-tokens {clientId} โ†’ invalidate that client's outstanding access tokens POST /__backdoor/revoke-refresh-token {refreshToken} โ†’ that refresh token stops working POST /__backdoor/rotate-signing-secret new webhook HMAC secret POST /__backdoor/fail-token-endpoint {clientId,times} โ†’ that client's next N token calls return 500 POST /__backdoor/webhooks/fire {url, event?, badSignature?} โ†’ POST a signed webhook there now POST /__backdoor/apps {publicKeyPem, appId?, installationId?, webhookSecret?} โ†’ register/replace a GitHub-App installation (public key only) POST /__backdoor/apps/fire-webhook {installationId?, url?, event?, badSignature?} โ†’ deliver (or, with no url, echo) a webhook signed x-hub-signature-256 with the app's webhookSecret Seeded client: petshop-default / petshop-default-secret ยท access tokens live 120s ยท webhooks are signed x-petshop-signature-256: sha256= ยท the backdoor is open unless PETSHOP_BACKDOOR_SECRET is set, in which case send it as x-petshop-backdoor. Seeded GitHub App: petshop-app ยท installation petshop-installation (register its RS256 public key via POST /__backdoor/apps) ยท installation tokens live 60s ยท App JWTs verify RS256 over header.payload and App webhooks sign x-hub-signature-256.