{"slug": "one-mcp-server-five-auth-shapes-per-seat-door-credentials-when-a-client-can-t-a", "title": "One MCP server, five auth shapes: per-seat door credentials when a client can't send a header", "summary": "A developer shipped Commons v0.5.0, an MCP server that accepts per-seat \"door credentials\" in five presentation shapes — Bearer header, URL path, URL query, X-Api-Key header, and Basic auth — all resolving through a single identity function. The change unblocked three URL-only model seats (ChatGPT, Gemini, Copilot) that could not send an Authorization header, without adopting OAuth. Each door secret is stored hashed, shown once at mint time, and revocable independently of the seat's root token.", "body_md": "Here's a problem I didn't expect to be the blocker.\n\nI had three model seats — ChatGPT, Gemini, Copilot — already working against one MCP server (my Canonical Vault, which does no transport credential check; governance lives server-side in branch rules). Those surfaces connect **URL-only**.\n\nMy newer MCP server, the Commons, accepted exactly one presentation: `Authorization: Bearer <token>`.\n\nResult: three credentialed seats, zero connections. Not a permissions problem. A *presentation* problem.\n\nOAuth was the obvious textbook answer — and the wrong first move. The seats didn't need a new identity system. They needed a door shaped like the one they already walk through.\n\nShip a per-seat secret that can be presented in whatever shape the client can actually send, all resolving through **one** identity function:\n\n| Presentation | Shape | \n|---|---|\n| Bearer (original) | `Authorization: Bearer <secret>` | \n| URL path | `POST /mcp/s/<secret>` | \n| URL query | `POST /mcp?k=<secret>` | \n| API key header | `X-Api-Key: <secret>` | \n| Basic password | `Authorization: Basic <user>:<secret>` | \n\nRules that make this safe enough to ship:\n\n`003_door_credentials`). The plaintext is shown once, at mint time, in a connection sheet the operator hands to that seat's surface.`authenticate()` path. No shape gets a weaker check. A bogus secret returns unauthenticated in `issue-door` / `revoke-door`. Revoking a seat's door does not touch its root token, and vice versa. I verified this on a throwaway door: revoked door → `revoked`, root token unaffected.\nCommons v0.5.0, in production:\n\n`/mcp/s/<secret>`, and `?k=` through the one identity function`whoami` through the door itself + every alternate shape, per seat`0.5.0`\nRemaining step is deliberately manual: add each door URL in that seat's own surface. Credentials cross into another vendor's UI only by the operator's hand.\n\nUse door credentials when:\n\nDon't use them when:\n\nI demoted OAuth and a REST shim to optional hardening, in that order. The unblocking move was meeting the clients at the presentation they already had — without weakening the one rule that matters: identity is a credential, never a claim, and the server derives it the same way no matter which door you came through.\n\n*Part of the \"Building Governed Agents\" series. Previous: \"The Commons: Claims, Never Commands.\" Code context: the Commons is an append-only MCP pool where models exchange claims under governance — source currently in a private repo, protocol described in the series. Paper: [doi.org/10.5281/zenodo.23242126](https://doi.org/10.5281/zenodo.23242126) · Writing: [liminaljermo.substack.com](https://liminaljermo.substack.com)*\n\n*Hit the same wall with an MCP client that can't send headers? I want to hear which shape you shipped.*", "url": "https://wpnews.pro/news/one-mcp-server-five-auth-shapes-per-seat-door-credentials-when-a-client-can-t-a", "canonical_source": "https://dev.to/liminaljermo/one-mcp-server-five-auth-shapes-per-seat-door-credentials-when-a-client-cant-send-a-header-j5o", "published_at": "2026-10-22 23:24:15+00:00", "updated_at": "2026-10-22 23:41:19.678052+00:00", "lang": "en", "topics": ["ai-agents", "agent-protocols", "ai-tools", "developer-tools"], "entities": ["Commons", "Canonical Vault", "ChatGPT", "Gemini", "Copilot", "MCP"], "also_reported_by": [], "alternates": {"html": "https://wpnews.pro/news/one-mcp-server-five-auth-shapes-per-seat-door-credentials-when-a-client-can-t-a", "markdown": "https://wpnews.pro/news/one-mcp-server-five-auth-shapes-per-seat-door-credentials-when-a-client-can-t-a.md", "text": "https://wpnews.pro/news/one-mcp-server-five-auth-shapes-per-seat-door-credentials-when-a-client-can-t-a.txt", "jsonld": "https://wpnews.pro/news/one-mcp-server-five-auth-shapes-per-seat-door-credentials-when-a-client-can-t-a.jsonld"}}