feat(auth): unauthenticated RFC 8414 on the MCP origin #94
No reviewers
Labels
No labels
blocked
bug
documentation
duplicate
enhancement
good first issue
help wanted
invalid
question
waiting-on-julian
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
jlxq0/matrix-mcp!94
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "feat/as-well-known"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Test plan
a0a389d308395b32c233Blocked on a finding, not on review capacity. Rebased onto
mainand pushed; the cargo gate had been red since 17 August on one unformattedassert_eq!in this file's own test, which is why it read as fifteen days of nobody looking. The gate now passes locally. What follows is why it should still not merge as written.Read against the question can this new code do the wrong thing in the case it was written for, and then checked against the live MAS document rather than against the RFCs alone.
issuernames the wrong serviceThe comment is the mistake. RFC 8414 §2 defines
issueras the authorization server's identifier, not the origin serving the document. Measured against the live MAS athttps://matrixauthservice.kampong.social:A client that records the metadata
issueras the expected authorization-server identity, sends the user to MAS, and then compares the RFC 9207issin the authorization response, comparesmatrixauthservice…againstmatrix-mcp…and must reject the code. That failure lands after the user has authenticated, which is the expensive place for it. And the trailing slash is load-bearing:MATRIX_MCP_AUTHORIZATION_SERVERis set tohttps://matrixauthservice.kampong.social/andauthorization_server_keeps_its_trailing_slashalready exists to preserve it, so the correct value iscfg.authorization_serververbatim rather than theauthorization_server_base()form used for the endpoints.The route cannot be made compliant, only less wrong
Setting
issuerto MAS does not rescue it. RFC 8414 §3.3 has the client check that the document's issuer matches the issuer it derived the retrieval URL from, and the retrieval URL here is our origin. So both values fail a strict client, one at retrieval and one after authentication. That is not an argument for either value; it is the reason to say plainly what this route is, which is a compatibility shim for MCP clients predating the 2025-06-18 move to RFC 9728.The strict path already works and needs none of this:
So a current client is told where to go by the 401 it already gets. This PR is for clients that do not read that header, and the PR should say so, because the next reader will otherwise take the route as the compliant one and the 9728 pair as legacy.
A hand-built copy of another service's document drifts, and this one already has
Two fields disagree with MAS today, before anything changes:
Both narrowings are safe in themselves and neither is the point. Nothing keeps the copy in step with MAS, no test compares them, and the three endpoint paths are string-built here rather than read from the source that defines them. They happen to match exactly today, which I checked:
That is a measurement of one afternoon, not a property.
registration_endpointis the one that bites hardest if it ever stops matching, since asserting it means a client doing dynamic registration POSTs there and the whole connection setup fails.A 302 to
https://matrixauthservice.kampong.social/.well-known/oauth-authorization-servercannot drift, gives a lenient client the authoritative document with MAS's own issuer in it, and fails a strict client at exactly the same place the copy does. It is fewer lines than the struct it replaces.What I would change before merging
issuertocfg.authorization_serververbatim and add a test that fetches MAS's document and compares the fields, so drift is a red build rather than a client's problem./mcpvariant or justify it. Its retrieval URL implies issuer…/mcp, which the document does not return under either candidate value.Cross-engine review by Codex found the
issuerfault and the §3.3 consequence; the drift measurement and the live-MAS comparison are mine. Codex also flaggedregistration_endpointas unsafe if MAS lacks RFC 7591, which does not hold here — MAS advertises it at exactly the constructed path.395b32c233bb1b4bde7fTwo mechanical blockers, both now fixed and pushed; the design finding above still stands.
The cargo gate had two failures stacked, and the first hid the second:
The second is caused by this PR and would have been caused by any PR adding a route.
too_many_linescounts the whole function, so the eight lines here tipped a function that was already at 95. Lifted the four.well-knownroutes intowell_known_routes() -> Router<Config>with no path, handler or ordering change.Gates run with CI's exact flags on 1.98.0, which is the pin in
ci.yml:And a note on how I nearly reported this wrong. My first three runs went through
build-slot.sh -- <cmd>, which the wrapper rejects with a usage error, so clippy and the tests never executed; I then read the background task's exit code, which was the last command in the compound rather than the one I cared about. Two of this repository's ownAGENTS.mdrules in one command. The numbers above come from runs whose rc was captured immediately after the command and before any pipe.So the state of this PR is: green mechanically, held on the
issuervalue and on whether this origin should serve a copy of MAS's document at all.blocked on #148. Mechanically green as of
bb1b4bd: rebased,cargo fmt --all --check,cargo clippy --all-targets --all-features --locked -D warningsandcargo test --all-features --lockedall rc=0 locally on the pinned 1.98.0, andCI / cargoandCI / dockerboth success on the forge.What remains is a decision rather than work: whether this origin serves a copy of MAS's RFC 8414 document, a 302 to it, or nothing. The measurements and the three options are in #148 so they outlive this PR and this session.
View command line instructions
Checkout
From your project repository, check out a new branch and test the changes.