Skip to content

feat: make OAUTH_RESOURCE the /mcp endpoint, and warn when audience is off - #63

Merged
marselsel merged 1 commit into
mainfrom
feat/audience-resource-indicator
Sep 22, 2026
Merged

marselsel merged 1 commit into
mainfrom
feat/audience-resource-indicator

Conversation

@marselsel

Copy link
Copy Markdown
Owner

Part 5 of 8 in the MCP best-practices stack. Stacked on #62, so merge in order.

Why

  • The spec requires it. MCP 2026-07-28 authorization: "MCP servers MUST validate that access tokens were issued specifically for them as the intended audience, according to RFC 8707". Production runs with OAUTH_VERIFY_AUDIENCE=false.
  • WorkOS now supports it. Resource indicators have been supported since May 2026 (blog, AuthKit MCP docs): "Access tokens will be issued with an aud claim that matches the requested resource." Without a configured resource indicator, AuthKit ignores resource and uses the environment's client ID as aud.
  • Claude's side (authentication, troubleshooting): the protected-resource metadata's resource "must match your MCP server URL exactly as the user enters it in Claude, including any path component". Claude sends that URL, path included, as the RFC 8707 resource. So OAUTH_RESOURCE should be https://host/mcp.
  • Why it wasn't possible before: following that advice broke the upload links. They were built from OAUTH_RESOURCE and would have pointed at https://host/mcp/upload/…, which doesn't exist.

Changes

  • Upload links: built from OAUTH_RESOURCE / SERVER_URL minus a trailing /mcp segment. A deployment under a path prefix keeps its prefix, and only a whole /mcp segment is dropped.
  • Startup warning: logged when OAuth runs with OAUTH_VERIFY_AUDIENCE=false.
  • Tested helper: the protected-resource metadata URL named in the 401 challenge moves into protectedResourceMetadataUrl. A test checks it against the path mcpAuthMetadataRouter actually serves for a /mcp resource.
  • Docs (README, docs/cloud-run.md, .env.example):
    • use https://…/mcp in all three places: the provider's resource indicator, OAUTH_RESOURCE, and what users enter in Claude
    • prefer Client ID Metadata Documents (off by default in WorkOS, under Connect → Configuration) over DCR, which the 2026-07-28 spec deprecates

Steps for the live deployment (not done by this PR)

Do these in order. Flipping the flag first rejects every token.

  1. In WorkOS (the tenant production actually uses), add https://<host>/mcp as a resource indicator.
  2. Deploy with OAUTH_RESOURCE=https://<host>/mcp, then reconnect the connector once, so new tokens carry aud=https://<host>/mcp.
  3. Remove OAUTH_VERIFY_AUDIENCE=false.
  4. Optional: enable CIMD. As of today the tenant's discovery document advertises neither CIMD nor registration_endpoint, so new users can't register a client. Existing connectors keep working.

Verification

  • Config tests cover the /mcp stripping (resource, SERVER_URL, path prefix, and a lexware-mcp path that must not be stripped) and the warning.
  • Over the wire, with OAUTH_RESOURCE=…/mcp:
    • /.well-known/oauth-protected-resource/mcp returns resource: …/mcp
    • the 401 challenge names that URL
    • the warning is logged
  • npm test passes all 479 tests.

…s off

Claude sends the URL users enter (path included) as the RFC 8707
resource and requires the protected-resource metadata to name it
exactly, so OAUTH_RESOURCE should be https://host/mcp. Upload links are
now built from that URL minus a trailing /mcp instead of pointing at a
route under /mcp that does not exist. The 401 challenge's metadata URL
moves into a tested helper.

Startup warns when OAUTH_VERIFY_AUDIENCE=false. The README and Cloud Run
guide now walk through registering the resource indicator (WorkOS
supports RFC 8707 since May 2026) and prefer CIMD over DCR, which the
2026-07-28 spec deprecates.
@marselsel
marselsel changed the base branch from feat/json-text-fallback to main September 22, 2026 21:57
@marselsel
marselsel merged commit 2c6ead8 into main Sep 22, 2026
2 checks passed
@marselsel
marselsel deleted the feat/audience-resource-indicator branch September 22, 2026 21:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant