Skip to content

Commit fea660f

Browse files
committed
fix: preserve existing refresh_token when server omits it in refresh response
Per RFC 6749 Section 6, issuing a new refresh token in the refresh response is optional. Many OAuth providers omit it by default (Google, Auth0 without rotation enabled, Okta in persistent token mode). This fix checks if the refresh response omits refresh_token and preserves the existing one to prevent auth failures after the first refresh. Fixes modelcontextprotocol#2304
1 parent 5388bea commit fea660f

1 file changed

Lines changed: 11 additions & 0 deletions

File tree

src/mcp/client/auth/oauth2.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -458,6 +458,17 @@ async def _handle_refresh_response(self, response: httpx.Response) -> bool: # p
458458
content = await response.aread()
459459
token_response = OAuthToken.model_validate_json(content)
460460

461+
# Preserve existing refresh_token when server omits it in refresh response
462+
# Per RFC 6749 Section 6, issuing a new refresh token is optional
463+
if (
464+
not token_response.refresh_token
465+
and self.context.current_tokens
466+
and self.context.current_tokens.refresh_token
467+
):
468+
token_response = token_response.model_copy(
469+
update={"refresh_token": self.context.current_tokens.refresh_token}
470+
)
471+
461472
self.context.current_tokens = token_response
462473
self.context.update_token_expiry(token_response)
463474
await self.context.storage.set_tokens(token_response)

0 commit comments

Comments
 (0)