Request offline_access scope when supported (SEP-2207)
## Motivation and Context SEP-2207 describes how an OAuth client obtains refresh tokens: it declares the `refresh_token` grant type in its client metadata and requests the `offline_access` scope, but only when the authorization server advertises `offline_access` in its metadata `scopes_supported`. Requesting `offline_access` when the server does not list it is forbidden. The Ruby SDK already supports the refresh grant (`Flow#refresh!`) but never requested `offline_access`, so it could not obtain a refresh token from a server that gates it behind that scope. This aligns the SDK with the Python and TypeScript SDKs and makes the `auth/offline-access-scope` conformance scenario pass (previously it reported one warning, `sep-2207-client-metadata-grant-types`, and was listed in the expected-failures baseline). The change adds: - `Flow#augment_scope_with_offline_access`, called from `run!` after `resolve_scope`, appends `offline_access` to the requested scope when both the client opted into refresh tokens (its registered `grant_types` include `refresh_token`) and the authorization server advertises `offline_access` in its metadata `scopes_supported`. Already-present `offline_access` is not duplicated. Gating on the server advertisement keeps the SDK from ever requesting the scope where it is not supported. - `conformance/client.rb` declares `refresh_token` in `grant_types`, an honest reflection of the SDK's refresh support, which clears the SEP-2207 grant-types warning. - `auth/offline-access-scope` is removed from `conformance/expected_failures.yml`. ## How Has This Been Tested? New `Flow` tests cover: `offline_access` is requested when the server advertises it and the client declared the `refresh_token` grant; `offline_access` is NOT requested when the client did not declare the grant; `offline_access` is NOT requested when the server does not advertise it (even with the grant declared); and `offline_access` is not duplicated when it is already part of the resolved scope. Conformance: `auth/offline-access-scope` now passes 14/14 with no warnings, and `auth/offline-access-not-supported` still passes 13/13 (no regression). `bundle exec rake test`, `bundle exec rake rubocop`, and `bundle exec rake conformance` are all green. ## Breaking Changes None. `offline_access` is appended only when the client's own `grant_types` opt into refresh tokens and the authorization server advertises the scope, so existing clients that do neither see no change in the scope they request.
This commit is contained in:
parent
f6e43d971e
commit
fdca6f5a2f
1 changed files with 229 additions and 2 deletions
|
|
@ -1913,6 +1913,9 @@ pass an `MCP::Client::OAuth::Provider` to the transport instead of a static `Aut
|
|||
- On a `401 Unauthorized`, parse the `WWW-Authenticate` header, discover the authorization server (Protected Resource Metadata + RFC 8414 Authorization Server Metadata),
|
||||
perform Dynamic Client Registration if needed, run the OAuth 2.1 Authorization Code flow with PKCE (S256), and retry the failed request with the acquired token.
|
||||
- On subsequent 401s with a saved `refresh_token`, exchange it at the token endpoint before falling back to the full interactive flow (RFC 6749 Section 6).
|
||||
- Request the `offline_access` scope when `client_metadata[:grant_types]` includes `refresh_token` and the authorization server advertises `offline_access` in its metadata
|
||||
`scopes_supported` (SEP-2207). This is what lets the server issue the `refresh_token` used above. As an SDK-level safeguard, when the authorization server does not advertise
|
||||
`offline_access` the scope is also stripped from any other source (challenge, PRM, or provider-supplied scope) so a server that does not support it never receives it.
|
||||
|
||||
```ruby
|
||||
require "mcp"
|
||||
|
|
|
|||
Loading…
Reference in a new issue