Hacktoberfest 2026: los issues que los mantenedores marcaron para octubre, abiertos y aptos para principiantes. Explorar issues de Hacktoberfest

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

Abierto Apto para principiantes
#1,330 0 comentarios 0 reacciones 0 asignados Ver en GitHub

Los mantenedores suelen responder en 3 días

@jstar0 ya está trabajando en esto.

Desde el 9/10/2026.

  • #1331 de @jstar0 — abierto

Evaluación

Dificultad
2/5
Tiempo estimado
1-3 horas
Aptitud para principiantes
65/100
Tipo de issue
Error
Claridad
Bien especificado
Estado de actividad
Activo
Stack tecnológico
rust

Línea de trabajo

Empieza en crates/rmcp/src/transport/auth.rs en refresh_token(), donde add_offline_access_if_supported se llama sobre los granted_scopes almacenados antes de construir la solicitud de refresh, y en la propia función auxiliar. Después lee la prueba refresh_token_adds_offline_access_when_as_supports_it, que actualmente espera offline_access en el refresh. Está terminado cuando las solicitudes de refresh envían solo los granted_scopes (o omiten scope), esa prueba se reescribe para coincidir y el comportamiento de la ruta de autorización de #897 no cambia.

Escrito por el modelo de indexación a partir del texto del issue.

Descripción

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.

Lenguaje dominante
Rust
Estrellas
4k
Forks
654
Merge medio
3 d 15 h
PR fusionados (30 d)
37

Preparar el entorno

Abrir en Codespaces

Inicia el contenedor de desarrollo del proyecto en tu navegador, con tu propia cuenta de GitHub.

Primeros pasos

  1. Lee el issue completo y luego la guía de contribución del proyecto.
  2. Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
  3. Haz un fork del repositorio y trabaja en una rama.
  4. Abre un pull request que haga referencia al número del issue.

Más de modelcontextprotocol/rust-sdk

Todos los issues de modelcontextprotocol/rust-sdk

Issues similares

Más issues de Rust

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.