Hacktoberfest 2026: die Issues, die Maintainer für den Oktober markiert haben – offen und einsteigerfreundlich. Hacktoberfest-Issues durchsuchen

auth: refresh_token() requests offline_access that was never granted, so refreshes fail with invalid_scope

Offen Anfängerfreundlich
#1,330 0 Kommentare 0 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen

Maintainer antworten meist innerhalb von 2 Tagen

@jstar0 arbeitet bereits daran.

Seit 09.10.2026.

  • #1331 von @jstar0 — offen

Bewertung

Schwierigkeit
2/5
Geschätzter Aufwand
1-3 Stunden
Anfängerfreundlichkeit
65/100
Issue-Typ
Bug
Klarheit
Klar beschrieben
Aktivitätsstatus
Aktiv
Tech-Stack
rust
Bereich
authentication

Rechercherichtung

Beginne in crates/rmcp/src/transport/auth.rs bei refresh_token(), wo add_offline_access_if_supported auf die gespeicherten granted_scopes aufgerufen wird, bevor der Refresh-Request aufgebaut wird, und bei der Hilfsfunktion selbst. Lies danach den Test refresh_token_adds_offline_access_when_as_supports_it, der aktuell offline_access im Refresh erwartet. Fertig ist, wenn Refresh-Requests nur die gewährten Scopes senden (oder scope weglassen), dieser Test entsprechend umgeschrieben ist und das Verhalten des Autorisierungspfads aus #897 unverändert bleibt.

Vom Indexierungsmodell aus dem Issue-Text verfasst.

Beschreibung

bug P1 ready for work T-security T-transport

Summary

Since #897, AuthorizationManager::refresh_token() adds offline_access to the refresh request whenever the authorization server lists it in scopes_supported, even if the stored grant doesn't include it. An authorization server that didn't grant offline_access refuses that refresh with invalid_scope. The client then has to re-authorize every time the access token expires.

Where

crates/rmcp/src/transport/auth.rs L2309-L2313:

let mut refresh_scopes = stored_credentials.granted_scopes.clone();
self.add_offline_access_if_supported(&mut refresh_scopes);
let requested_scopes = refresh_scopes.clone();
for scope in refresh_scopes {
    refresh_request = refresh_request.add_scope(Scope::new(scope));

The test added in #897, refresh_token_adds_offline_access_when_as_supports_it, expects a refresh of a grant holding only read to send offline_access read.

Why this breaks

RFC 6749 §6: the refresh request's scope "MUST NOT include any scope not originally granted by the resource owner". The authorization server is right to answer invalid_scope.

Requesting offline_access at authorization time doesn't guarantee it's granted. OIDC Core §11 requires prompt=consent alongside offline_access "unless other conditions for processing the request permitting offline access … are in place", and rmcp adds the scope without the prompt. node-oidc-provider, for one, drops offline_access from the grant by default. An OP can still issue a refresh token without the scope (node-oidc-provider allows this through its issueRefreshToken hook), and SEP-2207's own "No guarantee" item allows for that. Every refresh rmcp then sends is rejected:

POST /token
grant_type=refresh_token&refresh_token=…&scope=openid+profile+email+offline_access

HTTP/1.1 400 Bad Request
{"error":"invalid_scope","error_description":"refresh token missing requested scope","scope":"offline_access"}

SEP-2207, which #676/#897 implement, only covers authorization requests. Client guidance item 2: the client "MAY add the offline_access scope to the list of scopes from the resource server before making authorization requests to the Authorization Server". It doesn't extend that to refresh requests.

Reproduction

  1. Run an authorization server that strips offline_access without prompt=consent (node-oidc-provider 9.x does by default), still issues refresh tokens to the client (for node-oidc-provider, an issueRefreshToken that returns true for clients allowed the refresh_token grant), and lists offline_access in scopes_supported.
  2. Authorize with rmcp. The token response's scope doesn't include offline_access, but a refresh token is issued.
  3. Let the access token expire, or call refresh_token(). The token endpoint returns invalid_scope for offline_access.

Seen in the wild with Codex CLI 0.155.0 and 0.161.0 (codex-mcp-client, rmcp 3.3.0). Restricting Codex's configured scopes doesn't help: the login requests only the configured scopes, but every refresh still gets offline_access added. Still present on main (08e021153ef0).

Suggested fix

Don't add offline_access on the refresh path. Send the stored granted_scopes, or omit scope entirely, which RFC 6749 §6 defines as "equal to the scope originally granted". If the grant does include offline_access, it's already in granted_scopes, so nothing is lost. #897's scope-upgrade change is a re-authorization, so SEP-2207 does cover it and it can stay.

Vorherrschende Sprache
Rust
Sterne
4k
Forks
688
Ø Merge
4 T. 10 Std.
Gemergte PRs (30 T.)
37

Entwicklungsumgebung

In Codespaces öffnen

Startet den Dev-Container des Projekts im Browser, mit Ihrem eigenen GitHub-Konto.

Erste Schritte

  1. Lesen Sie das ganze Issue und danach den Beitragsleitfaden des Projekts.
  2. Schreiben Sie ins Issue, dass Sie es übernehmen — das erspart doppelte Arbeit.
  3. Forken Sie das Repository und arbeiten Sie in einem Branch.
  4. Öffnen Sie einen Pull Request, der die Issue-Nummer nennt.

Mehr aus modelcontextprotocol/rust-sdk

Alle Issues in modelcontextprotocol/rust-sdk

Ähnliche Issues

Weitere Issues zu Rust

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.