Commit graph rust-sdk/crates/rmcp/src/transport/auth.rs
Author SHA1 Message Date
Dale Seo
6a3b32d3ab
chore: add #[non_exhaustive] to remaining public structs (#768)
* chore: add #[non_exhaustive] to remaining public structs

* chore: add #[non_exhaustive] to remaining public types

* chore: enable exhaustive_structs/enums clippy lints

* test: add untagged ServerResult deserialization regression tests
2026-03-26 10:23:58 -04:00
Wils Dawson
a32a9c83a1
feat(auth): implement SEP-2207 OIDC-flavored refresh token guidance (#676)
* feat: implement sep-2207 refresh token guidance

* fix: update client-metadata.json to allow refresh tokens
2026-03-23 20:15:23 -04:00
Warwick
66712db808
fix(auth): redact secrets in Debug output for StoredCredentials and StoredAuthorizationState (#744)
* fix(auth): redact secrets in Debug output for StoredCredentials and StoredAuthorizationState

Removes `Debug` from the derive macros on `StoredCredentials` and
`StoredAuthorizationState` and replaces them with manual `Debug` impls
that print `[REDACTED]` for sensitive fields (access/refresh tokens,
PKCE verifiers, and CSRF tokens), preventing accidental credential
leakage via `{:?}` formatters, log calls, and error chains.

Fixes #741

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* test(auth): assert Debug output redacts secrets for credential types

Adds regression tests for the fix in the previous commit, verifying
that `{:?}` formatting of `StoredAuthorizationState` and
`StoredCredentials` does not emit plaintext secrets.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* test(auth): address review feedback on debug redaction tests

- Remove redundant VendorExtraTokenFields from use super:: in
  test_stored_credentials_debug_redacts_token_response (already
  imported at module scope)
- Add assert!(debug_output.contains("created_at")) to
  test_stored_authorization_state_debug_redacts_secrets to verify
  non-secret fields remain visible in Debug output
- Run cargo fmt

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Update crates/rmcp/src/transport/auth.rs

Co-authored-by: Dale Seo <5466341+DaleSeo@users.noreply.github.com>

* fix: remaining formatting issue

* fix: formatting

* fix: formatting

* fix: please

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Dale Seo <5466341+DaleSeo@users.noreply.github.com>
2026-03-13 15:51:02 -04:00
Dale Seo
54bb522e7f
feat: include granted scopes in OAuth refresh token request (#731)
* fix: include granted scopes in OAuth refresh token request

* docs: document scope forwarding in token refresh flow
2026-03-09 16:30:19 -04:00
Dale Seo
bb6c8043bf
feat: implement OAuth 2.0 Client Credentials flow (#707)
* feat: implement OAuth 2.0 Client Credentials flow

* fix: address SEP-1046 review findings

* fix: validate HTTPS on JWT token endpoint
2026-03-03 20:53:51 -05:00
Peter Siska
434ccb7812
fix(auth): pass WWW-Authenticate scopes to DCR registration request (#705)
* fix(auth): pass WWW-Authenticate scopes to DCR registration request

When an MCP server returns a 401 with `WWW-Authenticate: Bearer scope="..."`,
the scopes are parsed but never included in the Dynamic Client Registration
(DCR) request. Per RFC 7591, the DCR request should include a `scope` field
so the authorization server knows what scopes the client intends to use.
Servers that enforce scope-matching between registration and authorization
will reject the flow without this.

Changes:
- Add optional `scope` field to `ClientRegistrationRequest` with
  `skip_serializing_if` for backward compatibility
- Update `register_client()` to accept scopes parameter and include
  them in the DCR request body and returned `OAuthClientConfig`
- Thread scopes from `AuthorizationSession::new()` into both
  `register_client()` call sites
- Re-export `oauth2::TokenResponse` trait so consumers can extract
  scopes from token responses
- Add serialization tests for the new `scope` field

* refactor(auth): change register_client to accept &[&str] instead of &[String]

Avoids unnecessary Vec<String> allocation in callers that already have &[&str].

* fix(auth): make ClientRegistrationRequest crate-private

* refactor(auth): stop re-exporting oauth2 TokenResponse trait

* style(auth): merge TokenResponse into grouped oauth2 import

Fix nightly rustfmt check by consolidating the separate
`use oauth2::TokenResponse` into the existing `use oauth2::{...}` block.
2026-03-03 12:43:31 -05:00
Jack Amadeo
f63718d202
chore: add #[non_exhaustive] and mutation methods to improve compatibility (#715)
* chore: add #[non_exhaustive] to reduce backwards-incompatible changes going forward

* fix: remove ProtocolVersion import

* fix: add a few more with_ mutator methods

---------

Co-authored-by: Alex Hancock <alexhancock@block.xyz>
2026-03-03 10:38:01 -05:00
Guy Lichtman
78d959fcd4
feat(auth): support returning extra fields from token exchange (#700)
* feat(auth): support returning extra fields that may be returned from token generation

exchange_code_for_token and refresh_token now return a StandardTokenResponse which includes
any additionalfields which might have been sent by the vendor

BREAKING CHANGE: Return type of exchange_code_for_token and refresh_token has changed
and may require code changes.

* fix: doc links
2026-03-02 10:38:15 -05:00
Dale Seo
b967c132ae
fix: improve error logging and remove token secret from logs (#685) 2026-02-26 10:05:43 -05:00
Wils Dawson
83808d3114
fix: refresh token expiry (#680) 2026-02-24 12:02:50 -05:00
Dale Seo
021a431bef
chore: upgrade reqwest to 0.13.2 (#669) 2026-02-17 13:41:12 -05:00
Arc
016b7d3bfa
feat: add support for custom HTTP headers in StreamableHttpClient (#655)
* feat: add support for custom HTTP headers in StreamableHttpClient

* feat: implement reserved header checks for custom HTTP headers in StreamableHttpClient
2026-02-13 12:28:55 -05:00
Anar Azadaliyev
d9a5560953
feat(auth): add token_endpoint_auth_method to OAuthClientConfig (#648)
* feat(auth): add token_endpoint_auth_method to OAuthClientConfig

Some OAuth providers (e.g. HubSpot) require client credentials to be
sent as POST body parameters (client_secret_post) instead of via HTTP
Basic Auth header. The oauth2 crate defaults to BasicAuth, and rmcp
had no way to override this, causing TokenExchangeFailed errors.

Add an optional `token_endpoint_auth_method` field to OAuthClientConfig
that accepts "client_secret_post" (RequestBody) and "client_secret_basic"
(BasicAuth). Unknown values are silently ignored, preserving the default.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor(auth): derive token_endpoint_auth_method from server metadata

Move auth method selection from per-client config to server's
AuthorizationMetadata, which is the correct OAuth 2.0 approach.
Servers like HubSpot advertise token_endpoint_auth_methods_supported
in their metadata; reading it from there avoids manual configuration
and prevents TokenExchangeFailed errors with non-BasicAuth providers.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor(auth): read token_endpoint_auth_methods_supported from additional_fields

Move token_endpoint_auth_methods_supported out of AuthorizationMetadata
as an explicit field and read it from the serde(flatten) additional_fields
HashMap instead. This avoids serializing `null` when the field is absent,
which broke Zod validation in downstream consumers like MCP Inspector.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat(auth): prefer basic auth when both methods supported and improve test assertions

When token_endpoint_auth_methods_supported contains both client_secret_post
and client_secret_basic, default to basic auth per RFC 6749 §2.3.1.
Update configure_client tests to assert actual AuthType instead of is_some().

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* style(auth): apply cargo fmt formatting

* style(auth): apply nightly cargo fmt import grouping

* revert: undo .gitignore change

---------

Co-authored-by: Anar Azadaliyev <anar.azadaliye@gmail.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 09:56:07 -05:00
Wils Dawson
61845d61c4
11-25-2025 compliant Auth (#651)
* fix: correct discovery for AS metadata

* fix: add commitlint to dev container

* feat: add RFC 8707 support for resource parameter

* feat: pkce method verification

* feat(auth): implement SEP-835 scope handling and 403 upgrade flow

- add WWWAuthenticateParams for parsing scope and resource_metadata from headers
- add ScopeUpgradeConfig and scope tracking in AuthorizationManager
- add InsufficientScopeError and 403 handling in streamable HTTP client
- add scope union computation for progressive authorization
- export new public types: AuthClient, ScopeUpgradeConfig, WWWAuthenticateParams

Co-authored-by: fizy069 <fizy069@users.noreply.github.com>

* fix: reorg auth tests

* feat: add error to www-authenticate header parsing

* feat: consider protected resource metadata in scope selection

* fix: reorganize auth tests

* feat: add examples and docs for updated auth

---------

Co-authored-by: fizy069 <fizy069@users.noreply.github.com>
2026-02-12 11:30:13 -05:00
Guy Lichtman
f6ebc7af13
fix(auth): oauth metadata discovery (#641)
* fix(auth): oauth metadata discovery

* fix: format auth.rs
2026-02-04 17:57:52 +01:00
centdix
ce559f28e0
feat(auth): add StateStore trait for pluggable OAuth state storage (#614)
* feat(auth): add StateStore trait for pluggable OAuth state storage

* fix(examples): use CLI server_url for transport connection
2026-01-13 15:33:25 -05:00
Tanish Desai
61f7b7b99e
fix: add OpenID Connect discovery support per spec-2025-11-25 4.3 (#598)
* fix: add OpenID Connect discovery support per spec-2025-11-25 4.3

Previously only tried OAuth 2.0 endpoints. Now tries OAuth first, then
OpenID Connect Discovery 1.0 in the spec-mandated priority order.

Signed-off-by: tanish111 <tanishdesai37@gmail.com>

* fix: format auth.rs test assertions

Reformat assert_eq! statements to satisfy rustfmt checks in CI.

Signed-off-by: tanish111 <tanishdesai37@gmail.com>

---------

Signed-off-by: tanish111 <tanishdesai37@gmail.com>
2026-01-09 12:20:32 -05:00
David Stern
63d89b1a4e
fix: only try to refresh access tokens if we have a refresh token or an expiry time (#594) 2026-01-06 09:34:42 +08:00
Tanish Desai
f20ed202af
Add SEP-991 (CIMD) support for URL-based client IDs (#570)
* feat(auth): add cimd support for SEP-991

add cimd support for url-based client ids

Signed-off-by: tanish111 <tanishdesai37@gmail.com>

* test(auth): add unit tests for is_https_url helper

Add test coverage for is_https_url helper to validate HTTPS scheme, non-root paths,
and reject http, javascript, data schemes, and invalid inputs per SEP-991 requirements.

Signed-off-by: tanish111 <tanishdesai37@gmail.com>

* feat(example): add CIMD OAuth server for SEP-991 testing

Implements a new server example (servers_cimd_auth_streamhttp) that
demonstrates CIMD (Client ID Metadata Document) support for URL-based
client IDs. The server validates client_id URLs, fetches and validates
client metadata documents, and provides OAuth 2.0 authorization endpoints
with MCP integration for end-to-end testing.

Signed-off-by: tanish111 <tanishdesai37@gmail.com>

* fix(oauth): add CORS headers to token endpoint

Add CORS headers to token endpoint to allow cross-origin requests from browsers
during OAuth authorization code exchange flow.

Signed-off-by: tanish111 <tanishdesai37@gmail.com>

* refactor: improve is_https_url function and consolidate tests

- Improve is_https_url function formatting and readability
- Merge all test cases into single test_is_https_url_scenarios function
- Add missing test case for "https://" URL

Signed-off-by: tanish111 <tanishdesai37@gmail.com>

* refactor: use map_err instead of match for error handling in auth.rs

Replace the verbose match statement with
map_err for more idiomatic

Signed-off-by: tanish111 <tanishdesai37@gmail.com>

* feat: add client-metadata.json

Add client metadata file for SEP-991 CIMD
authentication support

Signed-off-by: tanish111 <tanishdesai37@gmail.com>

---------

Signed-off-by: tanish111 <tanishdesai37@gmail.com>
2025-12-10 08:55:38 -05:00
jokemanfire
bce0555068
fix(oauth): rfc8414 should judement the response_types (#485)
response_types_supported should be judement while try to do 'Authorization Code Flow'

Signed-off-by: jokemanfire <hu.dingyang@zte.com.cn>
2025-12-09 11:18:18 -05:00
adam jones
eb5a7f7408
feat!: remove SSE transport support (#562)
SSE transport has been removed from the MCP specification in favor of
streamable HTTP. This removes all SSE-specific transport code:

- Remove `transport-sse-client` and `transport-sse-server` features
- Remove `SseClientTransport` and `SseServer` types
- Remove SSE-specific examples (`counter_sse`, `counter_sse_directly`)
- Migrate auth examples from SSE to streamable HTTP
- Update tests to remove SSE transport usage
- Update documentation

BREAKING CHANGE: The following have been removed:
- `transport-sse-client` feature
- `transport-sse-client-reqwest` feature
- `transport-sse-server` feature
- `SseClientTransport` type
- `SseServer` type
- `sse_client` and `sse_server` modules

Users should migrate to streamable HTTP transport which provides
equivalent functionality. See `StreamableHttpClientTransport` and
`StreamableHttpService` for the replacement APIs.

Ref: https://github.com/modelcontextprotocol/rust-sdk/pull/561#issuecomment-3576551699
2025-12-01 20:40:13 -05:00
Måns
b6cbd39503
fix(oauth): let OAuth discovery skip to next well-known URL candidate on JSON parse error. (#545) 2025-11-18 09:21:25 +08:00
Alex Hancock
31be9b25b5
feat(auth): implement CredentialStore trait (#542) 2025-11-17 10:17:08 -05:00
Gabriel Peal
82f9b0976a
fix(oauth): respect oauth-protected-resource discovery (#511) 2025-11-05 09:19:13 -05:00
Gabriel Peal
dcbeb9b9bc
fix(oauth): fix oauth credential refresh (#509)
auth.rs was using an in-memory expires-at which is only set on initial token exchange.
Instead, this PR switches it to use the expires-at set in the credentials that are passed in.
2025-11-04 16:17:11 -05:00
Alex Hancock
d3ddc09e52
fix: do not manually construct fallback authorization metadata (#507) 2025-11-03 12:08:32 -05:00
Gabriel Peal
e98e0d05df
fix(oauth): three oauth discovery and registration issues (#489) 2025-10-20 20:49:43 -04:00
jokemanfire
6cd779c5d7
fix(oauth): dynamic client registration should be optional (#463)
Signed-off-by: jokemanfire <hu.dingyang@zte.com.cn>
2025-10-14 09:30:29 +08:00
Gabriel Peal
6011f34ddf
feat: allow clients to override client_name (#469)
Many MCP Servers use client_name for a variety of things including:
* Whitelisting
* Logos
* Copy shown directly on the page
* etc

As a result, it's important for MCP Clients to be able to override the client name.
2025-10-03 21:03:31 -04:00
Huabing (Robin) Zhao
0566d132ea
fix(oauth): support suffixed and preffixed well-knonw paths (#459)
Signed-off-by: Huabing Zhao <zhaohuabing@gmail.com>
2025-09-30 15:41:16 +08:00
Takeshi Yoneda
4c8f5ba7b3
fix(oauth): do not treat empty secret as valid for public clients (#443)
Signed-off-by: Takeshi Yoneda <t.y.mathetake@gmail.com>
2025-09-22 09:08:07 +08:00
Peter Nehrer
4ee2add899
bugfix: Non-empty paths in OAuth2 Authorization Server Metadata URLs (#441)
* fix: support non-empty paths in OAuth2 Authorization Server Metadata URLs

* fix: address formatting errors
2025-09-17 15:02:37 +08:00
David Stern
271cf0b232
fix(oauth): require CSRF token as part of the OAuth authorization flow. (#435)
* Require CSRF token as part of the authorization flow.

* Update auth example.

* Update docs/OAUTH_SUPPORT.md.
2025-09-12 09:27:11 +08:00
jokemanfire
048f1ac3af
fix(auth): url parse is not correct (#402)
The format method is not good for url.
2025-08-29 14:31:51 -04:00
Brendan Graham
98bf02df89
fix(oauth): expose OAuthTokenResponse publicly (#335) 2025-07-30 10:53:21 +08:00
Peter Nehrer
2077c8faff
fix: Explicitly added client_id as an extra parameter causes bad token requests (#322) 2025-07-22 09:06:52 +08:00
4t145
9a771fb157
refactor: Transport trait and worker transport, and streamable http client with those new features. (#167)
* refactor: a transport trait and streamable http client

* test: test with js streamable http server

* refactor: separate sse stream connection

* fix(test): streamable http client test with js

* fix(test): wait longer time for js server startup
2025-05-17 23:53:38 +08:00
Andrew Culberson
6c2e6e22ee
feat(oauth): fixes + cache client credentials (#157)
credentials optimize
2025-05-08 09:18:35 +08:00
jokemanfire
afb8a905e5
chore: add oauth2 support (#130)
1.add oauth2 server and client example
2.add oauth2 impl in sse
3.add auth doc 
Signed-off-by: jokemanfire <hu.dingyang@zte.com.cn>
2025-04-29 17:52:59 +08:00