{{ message }}
fix: retry token refresh without RFC 8707 resource param when the AS rejects it - #2853
Open
fede-kamel wants to merge 2 commits into
Open
fede-kamel wants to merge 2 commits into
fede-kamel wants to merge 2 commits into
Conversation
fede-kamel
force-pushed
the
fix/2578-refresh-resource-param
branch
from
August 19, 2026 02:49
cc4fd5f to
e8afa1a
Compare
Author
fede-kamel
force-pushed
the
fix/2578-refresh-resource-param
branch
from
August 20, 2026 21:32
e8afa1a to
d32f7c2
Compare
Author
|
@maxisbey could this get a look? It has been open since June 12 and #2578 still reproduces on today's main: with PRM present and protocol version 2025-06-18, the refresh request body is ['client_id', 'grant_type', 'refresh_token', 'resource'], and Entra ID v2.0 rejects the resource param on refresh_token grants (AADSTS9010010), so Entra-backed MCP clients lose auth every hour. I've just rebased onto main and slimmed the PR: the trailing-slash half was superseded by #2925 and is dropped, leaving only the refresh-grant fix. 151 auth tests pass, ruff clean. |
This comment was marked as spam.
This comment was marked as spam.
…rejects it Keeps the MCP-required resource parameter on refresh_token grants and adds a one-shot fallback: on a 400 whose error is not invalid_grant, the refresh is retried once without the resource param before falling back to full re-auth. Fixes Entra ID v2.0 (AADSTS9010010) interop without violating the MCP authorization profile.
fede-kamel
force-pushed
the
fix/2578-refresh-resource-param
branch
from
August 21, 2026 00:25
d32f7c2 to
69bfdbb
Compare
Author
…ces 100% coverage)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Motivation and Context
Fixes #2578.
Microsoft Entra ID v2.0 rejects the RFC 8707
resourceparameter onrefresh_tokengrants (AADSTS9010010, strictly enforced since March 2026). Because the SDK sends it on every refresh, MCP clients using Entra OAuth lose authentication after ~1 hour: the silent refresh fails, tokens are cleared, and the user is forced through interactive re-auth every hour.At the same time, the MCP authorization spec (2025-06-18 and later, "Resource Parameter Implementation") requires the
resourceparameter in token requests, and RFC 8707 §2.2 defines it for all grant types including refresh. So unconditionally omitting it on refresh (this PR's original approach) would trade the Entra bug for a spec violation — thanks to the review feedback below for pushing on this.This PR now keeps the spec-required behavior and adds a targeted fallback:
resourceparameter is still sent on refresh requests exactly as before.invalid_grant, the refresh is retried once without theresourceparameter before falling back to full re-authentication.invalid_grant(a dead refresh token) never triggers the retry, since resending withoutresourcecannot help.For conformant authorization servers nothing changes. For Entra-style servers, the cost is one extra request on an already-failing path, instead of an hourly interactive re-auth.
How Has This Been Tested?
tests/client/test_auth.py+tests/interaction/auth/test_lifecycle.py: 155 passed, 1 xfailed (uv run --frozen pytest)TestRefreshResourceParamFallbackcovers: the Entra-style 400 → retry withoutresource→ success path; retry failure → full re-auth;invalid_grant→ no retry; old protocol version (noresourcesent) → no retryruff checkandruff formatcleanBreaking Changes
None. Default behavior is unchanged for all conformant authorization servers; the retry only engages after a 400 rejection that is not
invalid_grant.Types of changes
Checklist