Hacktoberfest 2026 : les issues que les mainteneurs ont marquées pour octobre, ouvertes et accessibles aux débutants. Parcourir les issues Hacktoberfest

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

Ouverte Adaptée aux débutants
#1,330 0 commentaires 0 réactions 0 personnes assignées Voir sur GitHub

Les mainteneurs répondent en général sous 3 jours

@jstar0 y travaille déjà.

Depuis le 9/10/2026.

  • #1331 par @jstar0 — ouverte

Évaluation

Difficulté
2/5
Temps estimé
1-3 heures
Accessibilité débutants
65/100
Type d'issue
Bug
Clarté
Clairement spécifiée
Activité
Active
Stack technique
rust
Domaine
authentication

Piste de recherche

Commence dans crates/rmcp/src/transport/auth.rs à refresh_token(), là où add_offline_access_if_supported est appelée sur les granted_scopes stockés avant la construction de la requête de rafraîchissement, puis examine la fonction auxiliaire elle-même. Lis ensuite le test refresh_token_adds_offline_access_when_as_supports_it, qui attend actuellement offline_access dans le rafraîchissement. C'est terminé lorsque les requêtes de rafraîchissement n'envoient que les granted_scopes (ou omettent scope), que ce test est réécrit en conséquence et que le comportement du chemin d'autorisation de #897 reste inchangé.

Rédigé par le modèle d'indexation à partir du texte de l'issue.

Description

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.

Langage dominant
Rust
Étoiles
4.1k
Forks
680
Merge moyen
4 j 13 h
PR mergées (30 j)
36

Préparer son environnement

Ouvrir dans Codespaces

Lance le conteneur de développement du projet dans votre navigateur, avec votre propre compte GitHub.

Par où commencer

  1. Lisez l'issue en entier, puis le guide de contribution du projet.
  2. Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
  3. Forkez le dépôt et travaillez sur une branche.
  4. Ouvrez une pull request qui référence le numéro de l'issue.

Autres issues de modelcontextprotocol/rust-sdk

Toutes les issues de modelcontextprotocol/rust-sdk

Issues similaires

Plus d'issues Rust

Recevez les nouvelles issues par e-mail

Un résumé court des issues GitHub adaptées aux débutants.