Skip to content

fix: canonical resource URI + log rejected DCR redirect_uris for OAuth#43

Merged
imonroe merged 2 commits into
mainfrom
claude/zen-babbage-eOZ3p
May 23, 2026
Merged

fix: canonical resource URI + log rejected DCR redirect_uris for OAuth#43
imonroe merged 2 commits into
mainfrom
claude/zen-babbage-eOZ3p

Conversation

@imonroe
Copy link
Copy Markdown
Owner

@imonroe imonroe commented May 23, 2026

Two fixes for OAuth MCP connections (Claude.ai web / Cowork), found while debugging a live deployment with container logs.

1. Advertise the canonical resource URI without a trailing slash (the connection blocker)

After the redirect-URI allowlist was corrected, the full OAuth flow succeeded in the logs — register → 201, authorize → 302, token → 200, and authenticated POST /mcp/ → 200 calls processing ListToolsRequest — yet Claude still reported "Authorization with the MCP server failed."

Root cause: our protected-resource metadata advertised resource: https://<host>/mcp/ (trailing slash), but Claude canonicalizes the resource to the no-slash form and sends resource=https://<host>/mcp (visible in the /oauth/authorize query in the logs). The MCP authorization spec is explicit:

"while trailing slashes are technically valid in absolute URIs, implementations should consistently omit them unless semantically significant"

So Claude's post-token resource-identity check failed on the mismatch. Fix: advertise https://<host>/mcp (no slash), matching the client's canonical form. The token already works against /mcp/ (proven by the 200s), so this is purely the advertised identifier.

2. Log rejected DCR redirect_uris (diagnostic)

POST /oauth/register returned a bare 400 with no record of the rejected redirect_uri, which made the earlier "callback not allowlisted" failure hard to diagnose. Now logs a dcr_redirect_uri_rejected warning with the requested URIs and the active allowed list.

Verification

  • 64 tests pass; ruff clean. Metadata tests updated to assert the no-slash canonical resource.
  • User Guide troubleshooting updated for the DCR-rejection case.

https://claude.ai/code/session_01U3EtN3puoZRq2t7nedcnHY

When a Dynamic Client Registration request is rejected because the
client's redirect_uri isn't in OAUTH_ALLOWED_REDIRECT_URIS, the server
returned a bare 400 with no record of what was actually requested. This
is the common cause of Claude.ai web / Cowork connections failing right
after discovery succeeds.

Log a dcr_redirect_uri_rejected warning with the requested URIs and the
active allowlist so the exact value can be added to the env var. Document
the symptom and remedy in the user guide.

https://claude.ai/code/session_01U3EtN3puoZRq2t7nedcnHY
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds diagnostic visibility for OAuth Dynamic Client Registration failures when clients submit redirect URIs outside the configured allowlist, and documents the troubleshooting path for operators.

Changes:

  • Adds structured warning logging for rejected /oauth/register redirect URIs.
  • Includes requested, rejected, and allowed redirect URI lists in the diagnostic log.
  • Updates the User Guide troubleshooting table with the new log event and remediation.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
app/oauth.py Logs rejected DCR redirect URI attempts before returning 400.
docs/USER_GUIDE.md Documents the new DCR rejection symptom and fix.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

The protected-resource metadata advertised the resource as
"<base>/mcp/" (trailing slash), but MCP clients (Claude.ai web / Cowork)
canonicalize the resource to the no-slash form "<base>/mcp" per the MCP
authorization spec ("implementations should consistently omit [trailing
slashes]") and send that as the RFC 8707 resource indicator. The
mismatch caused Claude to reject authorization after a token was already
issued, even though authenticated /mcp/ calls succeeded.

Advertise "<base>/mcp" so the advertised resource matches the client's
canonical form.

https://claude.ai/code/session_01U3EtN3puoZRq2t7nedcnHY
@imonroe imonroe changed the title feat: log rejected DCR redirect_uris to diagnose OAuth connect failures fix: canonical resource URI + log rejected DCR redirect_uris for OAuth May 23, 2026
@imonroe imonroe merged commit 9234c15 into main May 23, 2026
1 check passed
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.

3 participants