You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
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.
Copy file name to clipboardExpand all lines: README.md
+3Lines changed: 3 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1913,6 +1913,9 @@ pass an `MCP::Client::OAuth::Provider` to the transport instead of a static `Aut
1913
1913
- On a `401 Unauthorized`, parse the `WWW-Authenticate` header, discover the authorization server (Protected Resource Metadata + RFC 8414 Authorization Server Metadata),
1914
1914
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.
1915
1915
- 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).
1916
+
- Request the `offline_access` scope when `client_metadata[:grant_types]` includes `refresh_token` and the authorization server advertises `offline_access` in its metadata
1917
+
`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
1918
+
`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.
0 commit comments