FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

Comparing main...feat-client-auth · modelcontextprotocol/php-sdk · GitHub

Repository navigation

Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: modelcontextprotocol/php-sdk
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: main
Choose a base ref
Could not load branches
Nothing to show
{{ refName }}
...
head repository: modelcontextprotocol/php-sdk
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: feat-client-auth
Choose a head ref
Could not load branches
Nothing to show
{{ refName }}
Checking mergeability… Don’t worry, you can still create the pull request.
  • 5 commits
  • 68 files changed
  • 1 contributor

Commits on Sep 27, 2026

  1. [Client] Add OAuth authorization to the HTTP transport

    Pass `auth:` to `HttpTransport` and a 401 turns into discovery, an
    authorization code and a token, then a retry. `Mcp\Client\Auth\OAuth`
    builds the authenticator; `BearerToken` sends one you already have.
    
    Covers RFC 9728/8414 discovery, PKCE, dynamic registration, the four
    token endpoint auth methods, scope selection and step-up, refresh,
    client credentials, cross-app access, and the RFC 9207 iss check.
    
    Closes #315, #316, #317, #318, #319, #320, #321, #322, #323, #324,
    #325, #326, #329, #360, #361, #363, #376, #377
    chr-hertel committed Sep 27, 2026
    Configuration menu
    Copy the full SHA
    db38f2c View commit details
    Browse the repository at this point in the history
  2. [Client] Harden the OAuth client against a hostile server

    Six changes, from reviewing the flow with the MCP server treated as
    attacker-controlled — it picks the challenge, the metadata, and thus
    the authorization server.
    
    * Only attach a token to a request within the resource it was minted
      for. The transport builds one authenticator per endpoint, but nothing
      stopped a caller sharing one across two servers.
    * Require `state` on the authorization response instead of checking it
      only when present. The loopback listener accepts a connection from any
      local process, and an absent state skipped the binding entirely.
    * Stop logging the redirect Location, which carried the authorization
      code. Log the parameter names instead.
    * Refuse authorization, token and registration endpoints that are not
      https, unless the host is loopback.
    * Write the credential file through a 0600 temporary file and rename it
      into place, so it is never briefly world-readable or half-written.
    * Default `legacyDiscovery` to off. A server that publishes no protected
      resource metadata leaves nothing to check its authorization server
      against; `setLegacyDiscovery(true)` opts back in.
    
    The console handler no longer accepts a bare authorization code, since
    one carries neither state nor iss to check.
    
    Conformance unchanged: 234/241 on 2025-11-25, 405/405 on 2026-07-28,
    and both 2025-03-26 scenarios still pass with legacy discovery enabled.
    chr-hertel committed Sep 27, 2026
    Configuration menu
    Copy the full SHA
    53d958d View commit details
    Browse the repository at this point in the history
  3. [Client] Only follow a same-origin resource metadata location

    The `resource_metadata` parameter of the challenge is chosen by the
    server, and the client fetched whatever it named. That is a request
    made on the server's behalf, to a host it picked, from wherever the
    client runs — which may be inside a network the server cannot reach.
    
    RFC 9728 derives the location from the resource identifier, so a
    document describing this resource lives on this resource. A location
    anywhere else is now ignored and the well-known paths are probed
    instead, exactly as for a challenge that named none.
    chr-hertel committed Sep 27, 2026
    Configuration menu
    Copy the full SHA
    ff7347a View commit details
    Browse the repository at this point in the history
  4. [Client] Close the remaining SSRF vector and stop quoting token bodies

    From a second review pass over the same threat model.
    
    * Validate the authorization server issuer before its metadata is
      fetched. The https check sat in `fromArray()`, which only ever sees a
      response body — so `authorization_servers: ["http://10.0.0.5:8080/x"]`
      still produced two GETs to that host before anything objected.
    * Never quote a 200 response body into the token exception. The guard
      fired on "200 but not JSON" too, so a token endpoint answering
      form-encoded put a live access token into a message that reaches the
      application and its logs.
    * Bind the token to the resource the server published, not to the
      RFC 8707 `resource` parameter. Overriding that parameter chooses which
      token to ask for, not where it may be spent — as written, the guard
      added in 8ebdc85 dropped the header forever and re-ran the browser
      flow on every request.
    * Unescape challenge parameters the way HTTP defines it, one backslash
      before one character, rather than as C escapes.
    * Refuse to hand a non-HTTPS URL to the desktop's URL opener.
    chr-hertel committed Sep 27, 2026
    Configuration menu
    Copy the full SHA
    2063584 View commit details
    Browse the repository at this point in the history
  5. [Client] Sign client assertions with firebase/php-jwt

    Replaces the hand-rolled RFC 7523 assertion, including the ECDSA
    DER-to-JOSE conversion, with the library the server side already uses
    for the other direction. `TokenEndpoint` goes from 237 to 182 lines and
    loses the most delicate code in the component.
    
    Suggested rather than required, and guarded with class_exists like
    `JwtTokenValidator` is: private_key_jwt is the only path that needs it.
    
    Signing with the HMAC family is now refused outright. That is what
    `client_secret_jwt` uses, and handing it a private key would sign the
    assertion with the key material as a shared secret — a downgrade the
    hand-rolled version could not express, since it only knew RS and ES.
    
    Gains PS256, ES256K and EdDSA; loses ES512, which the library does not
    support. The conformance ES256 scenario still passes 8/8.
    chr-hertel committed Sep 27, 2026
    Configuration menu
    Copy the full SHA
    93ede9b View commit details
    Browse the repository at this point in the history
Loading

Back | FazBrowse Home | New Git URL