Repository navigation
fix(mcp): DCR must return srv-mcp's clientid, not the approuter's own - #2711
Merged
Merged
Conversation
Live DEV verification of #2710 (DCR) exposed the bug it was meant to kill, relocated into the proxy. POST /mcp-oauth/register returned cf2ea5eb… — the approuter's OWN tutorials-identity clientid — but tutorials-srv-mcp validates token `aud` against 0b1e8b56… (its separate tutorials-identity instance). A native-HTTP client registering via DCR would get cf2ea5eb…, complete login, and hit WrongAudience 401 at /mcp-auth/api — the same aud-mismatch class, just moved. Root cause: resolveIasClientId() trusted the approuter's VCAP identity binding, on the (false) assumption from #2593 that the approuter binds the SAME identity instance as srv-mcp. It does not — verified DEV 2026-10-11: - approuter → instance tutorials-approuter-identity, clientid cf2ea5eb… - srv-mcp → instance tutorials-identity, clientid 0b1e8b56… same tenant app_tid (3c6fa3f1…), distinct clients. @sap/xssec kind:ias checks aud === credentials.clientid exactly, so cf2ea5eb… cannot pass srv-mcp. Fix: resolveIasClientId() now prefers an explicit MCP_RESOURCE_CLIENT_ID env (srv-mcp's clientid, pinned per-env in the mtaext — DEV 0b1e8b56…, PROD 5a7cb5fd…), falling back to the VCAP binding only when unset. Deterministic; no shared-binding assumption. The DCR response is otherwise unchanged (public client, no secret, redirect_uris echoed for the client↔proxy leg only). - approuter/lib/mcp-consent.js: MCP_RESOURCE_CLIENT_ID precedence + corrected comment - deploy/dev.mtaext + deploy/prod.mtaext: pin srv-mcp's per-env clientid - tests: +3 (precedence over VCAP, /register returns the env value, empty-env falls back to VCAP); saveEnv tracks MCP_RESOURCE_CLIENT_ID; 63 green
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Follow-up fix to #2710 (DCR). Live DEV probe of the DCR endpoint returned the wrong client_id — the approuter's own
tutorials-identityclientid (cf2ea5eb…) instead of the onetutorials-srv-mcpvalidates tokenaudagainst (0b1e8b56…). A native-HTTP OAuth client registering via DCR would complete login and then hit WrongAudience 401 at/mcp-auth/api— the exact bug class #2710 set out to eliminate, just relocated into the proxy.Root cause
resolveIasClientId()read the approuter's VCAPidentitybinding, on the (incorrect) #2593 assumption that the approuter binds the same identity instance as srv-mcp. It does not — verified on DEV 2026-10-11:tutorials-dev-approuter(runs/register)tutorials-approuter-identitycf2ea5eb…tutorials-srv-mcp(validatesaud)tutorials-identity0b1e8b56…Same tenant
app_tid(3c6fa3f1…), distinct clients.@sap/xsseckind:iaschecksaud === credentials.clientidexactly, socf2ea5eb…can never pass srv-mcp.Fix
resolveIasClientId()now prefers an explicitMCP_RESOURCE_CLIENT_IDenv (srv-mcp's clientid, pinned per-env in the mtaext — DEV0b1e8b56…, PROD5a7cb5fd…), falling back to the VCAP binding only when unset. Deterministic; no shared-binding assumption. DCR response shape otherwise unchanged (public client, no secret).Verification
/registerreturns env value, empty-env falls back to VCAP).yq-validated, correct per-env clientids,app-nameintact.POST /mcp-oauth/register→ expectclient_id=0b1e8b56…; then native-HTTP OAuth end-to-end (Tom drives browser login).🤖 Generated with Claude Code