Skip to content

Default to client_secret_basic when server omits token_endpoint_auth_methods_supported#1594

Open
bhosmer-ant wants to merge 3 commits intomainfrom
fix/bug-066-client-auth-default
Open

Default to client_secret_basic when server omits token_endpoint_auth_methods_supported#1594
bhosmer-ant wants to merge 3 commits intomainfrom
fix/bug-066-client-auth-default

Conversation

@bhosmer-ant
Copy link
Contributor

When an authorization server's metadata omits token_endpoint_auth_methods_supported, the SDK currently defaults to client_secret_post. Per RFC 8414 §2, the default in this case is client_secret_basic:

token_endpoint_auth_methods_supported [...] If omitted, the default is "client_secret_basic" -- the HTTP Basic Authentication Scheme specified in Section 2.3.1 of OAuth 2.0 [RFC6749].

RFC 6749 §2.3.1 also requires compliant servers to support HTTP Basic for clients with a secret, making it the safest default.

This PR:

  • Changes the default from client_secret_post to client_secret_basic when supportedMethods is empty
  • Also honors the DCR-returned token_endpoint_auth_method when supportedMethods is empty (previously the early return swallowed the DCR hint in this scenario)
  • Updates 5 existing tests that were implicitly relying on the old default
  • Adds 3 new tests covering the empty-supportedMethods scenarios

Related to #951 — PR #1022 fixed the DCR-preference case when server metadata is present, but left the omitted-metadata default untouched. This PR addresses the remaining case.

Motivation and Context

A server that doesn't publish token_endpoint_auth_methods_supported but follows RFC 6749 is guaranteed to accept HTTP Basic auth for confidential clients. A server that only accepts client_secret_post and doesn't advertise that fact is non-compliant — our default shouldn't cater to that case.

How Has This Been Tested?

  • 3 new unit tests for selectClientAuthMethod with empty supportedMethods (confidential client, public client, DCR-hint-present)
  • Updated exchangeAuthorization / refreshAuthorization integration tests to verify HTTP Basic auth header is sent when no metadata is provided
  • All 133 auth tests pass

Breaking Changes

Behavioral change for clients talking to servers that omit token_endpoint_auth_methods_supported from their metadata: the SDK will now send credentials via HTTP Basic auth (Authorization header) instead of in the request body. This aligns with RFC 8414/6749 and should work against any compliant server. Servers that were only accepting body-param auth without advertising it will need to either advertise client_secret_post in their metadata or accept Basic auth.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update

Checklist

  • I have read the MCP Documentation
  • My code follows the repository's style guidelines
  • New and existing tests pass locally
  • I have added appropriate error handling
  • I have added or updated documentation as needed

Additional context

Follow-up identified: applyBasicAuth at line ~345 does raw btoa(\${clientId}:${clientSecret}`)without percent-encoding the components first, as required by RFC 6749 §2.3.1. This is a pre-existing bug that this PR surfaces more frequently by makingclient_secret_basicthe default. The fix isencodeURIComponent()on both components beforebtoa()`. Tracked separately to keep this PR focused.

…methods_supported

Per RFC 8414 §2, when an authorization server's metadata omits
token_endpoint_auth_methods_supported, the default is client_secret_basic,
not client_secret_post. RFC 6749 §2.3.1 also requires servers to support
HTTP Basic authentication for clients with a secret, making it the safest
default.

Also: honor the DCR-returned token_endpoint_auth_method even when
supportedMethods is empty — previously the early return swallowed the
DCR hint in this scenario.

Related to #951 (PR #1022 fixed the DCR-preference case when metadata IS
present, but left this RFC-default case untouched).
@bhosmer-ant bhosmer-ant requested a review from a team as a code owner February 26, 2026 19:04
@changeset-bot
Copy link

changeset-bot bot commented Feb 26, 2026

⚠️ No Changeset found

Latest commit: 63bce0c

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@pkg-pr-new
Copy link

pkg-pr-new bot commented Feb 26, 2026

Open in StackBlitz

@modelcontextprotocol/client

npm i https://pkg.pr.new/modelcontextprotocol/typescript-sdk/@modelcontextprotocol/client@1594

@modelcontextprotocol/server

npm i https://pkg.pr.new/modelcontextprotocol/typescript-sdk/@modelcontextprotocol/server@1594

@modelcontextprotocol/express

npm i https://pkg.pr.new/modelcontextprotocol/typescript-sdk/@modelcontextprotocol/express@1594

@modelcontextprotocol/hono

npm i https://pkg.pr.new/modelcontextprotocol/typescript-sdk/@modelcontextprotocol/hono@1594

@modelcontextprotocol/node

npm i https://pkg.pr.new/modelcontextprotocol/typescript-sdk/@modelcontextprotocol/node@1594

commit: 1943276

The mock auth servers in sse.test.ts validated client credentials by
checking body params (client_secret_post). With the default changed
to client_secret_basic, credentials now arrive in the Authorization
header instead. Updated the three affected mock servers to parse and
validate HTTP Basic auth headers.
@mattzcarey
Copy link
Contributor

mattzcarey commented Feb 27, 2026 via email

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.

2 participants