Environment
- CLI version:
1.0.56-1
- OS: Windows 11
- MCP servers: custom Azure Container Apps with Entra (AAD) OAuth, audience app
8d9aefa8-8693-45ef-8956-fa6584dfa06f, tenant 72f988bf-86f1-41af-91ab-2d7cd011db47
Summary
After roughly 60–70 minutes of idle (i.e. one access-token lifetime), every MCP tool call fails the silent token refresh with:
AADSTS90009: Application '8d9aefa8-8693-45ef-8956-fa6584dfa06f' is requesting a token for itself. This scenario is supported only if resource is specified using the GUID based App Identifier.
Sample trace IDs:
478b71ad-30c8-4252-b6e1-aba020220a00
84729b2e-b3b9-4e0c-9071-1fa010b40300
28cd1339-4aa5-4ef6-adef-d600fdf48b49
Once it starts, every subsequent tool call returns the same error indefinitely until the on-disk token cache is hand-patched. /mcp auth <server> from a new session also frequently returns the adjacent error AADSTS90023: Unsupported 'prompt' value (likely related — same auth path).
Repro
/mcp auth <server> — succeeds, tokens land in ~/.copilot/mcp-oauth-config/<hash>.tokens.json.
- Idle the session longer than the access-token lifetime (~60 min).
- Invoke any MCP tool →
AADSTS90009.
- Retrying the tool, restarting the session, or re-running
/mcp auth does not clear the failure.
Root cause analysis
The cached refresh_token is healthy. I verified this by replaying it directly against Entra's v2 endpoint:
POST https://login.microsoftonline.com/<tenant>/oauth2/v2.0/token
Content-Type: application/x-www-form-urlencoded
client_id=8d9aefa8-8693-45ef-8956-fa6584dfa06f
grant_type=refresh_token
refresh_token=<exact value from the CLI's cache file>
scope=api://8d9aefa8-8693-45ef-8956-fa6584dfa06f/access_as_user offline_access
→ HTTP 200, returns a fresh access_token + rotated refresh_token. Writing those back into the cache file restores the session for another ~60 min, after which the same failure recurs.
The AADSTS90009 "app requesting token for itself" text is Entra's canonical response when a confidential/public client sends its own clientId as the v1 resource= parameter against the v2 token endpoint. Combined with the fact that the same refresh_token works fine when paired with the v2 scope=api://<clientId>/access_as_user form, this strongly suggests the CLI's silent-refresh code path is sending v1-style resource=<clientId> instead of v2-style scope=api://<clientId>/access_as_user offline_access when refreshing tokens for custom OAuth MCP servers.
The initial interactive /mcp auth flow uses the correct v2 form (since the first sign-in works), so the bug appears to be isolated to the silent-refresh path.
Expected
Silent refresh should use the v2 scope= parameter that matches the original interactive sign-in, so the cached refresh_token continues to mint new access tokens every ~60 min without user intervention.
Actual
Silent refresh returns AADSTS90009 indefinitely. The session is effectively dead until the cache is hand-patched.
Workaround
PowerShell script that reads each ~/.copilot/mcp-oauth-config/<hash>.tokens.json, calls Entra v2 with the correct scope= body, and writes the new tokens back. Has to be run roughly hourly. Happy to share if useful.
Impact
Any long-running session against a custom OAuth MCP server becomes unusable after ~70 min. The CLI is the only client we have that exhibits this; same MI/refresh_token works fine from az rest, browser, or raw curl.
Asks
- Fix the silent-refresh path to use
scope= (v2) instead of resource= (v1) for MCP servers configured with custom OAuth scopes.
- Investigate
AADSTS90023: Unsupported 'prompt' value on fresh-session /mcp auth (likely same code path, different prompt parameter).
- If a fix is in flight, an interim
/mcp refresh <server> command that re-runs the interactive flow without nuking other MCP caches would unblock us.
Happy to provide HAR captures, additional trace IDs, or test patches.
Environment
1.0.56-18d9aefa8-8693-45ef-8956-fa6584dfa06f, tenant72f988bf-86f1-41af-91ab-2d7cd011db47Summary
After roughly 60–70 minutes of idle (i.e. one access-token lifetime), every MCP tool call fails the silent token refresh with:
Sample trace IDs:
478b71ad-30c8-4252-b6e1-aba020220a0084729b2e-b3b9-4e0c-9071-1fa010b4030028cd1339-4aa5-4ef6-adef-d600fdf48b49Once it starts, every subsequent tool call returns the same error indefinitely until the on-disk token cache is hand-patched.
/mcp auth <server>from a new session also frequently returns the adjacent error AADSTS90023: Unsupported 'prompt' value (likely related — same auth path).Repro
/mcp auth <server>— succeeds, tokens land in~/.copilot/mcp-oauth-config/<hash>.tokens.json.AADSTS90009./mcp authdoes not clear the failure.Root cause analysis
The cached
refresh_tokenis healthy. I verified this by replaying it directly against Entra's v2 endpoint:→ HTTP 200, returns a fresh
access_token+ rotatedrefresh_token. Writing those back into the cache file restores the session for another ~60 min, after which the same failure recurs.The
AADSTS90009 "app requesting token for itself"text is Entra's canonical response when a confidential/public client sends its own clientId as the v1resource=parameter against the v2 token endpoint. Combined with the fact that the same refresh_token works fine when paired with the v2scope=api://<clientId>/access_as_userform, this strongly suggests the CLI's silent-refresh code path is sending v1-styleresource=<clientId>instead of v2-stylescope=api://<clientId>/access_as_user offline_accesswhen refreshing tokens for custom OAuth MCP servers.The initial interactive
/mcp authflow uses the correct v2 form (since the first sign-in works), so the bug appears to be isolated to the silent-refresh path.Expected
Silent refresh should use the v2
scope=parameter that matches the original interactive sign-in, so the cached refresh_token continues to mint new access tokens every ~60 min without user intervention.Actual
Silent refresh returns
AADSTS90009indefinitely. The session is effectively dead until the cache is hand-patched.Workaround
PowerShell script that reads each
~/.copilot/mcp-oauth-config/<hash>.tokens.json, calls Entra v2 with the correctscope=body, and writes the new tokens back. Has to be run roughly hourly. Happy to share if useful.Impact
Any long-running session against a custom OAuth MCP server becomes unusable after ~70 min. The CLI is the only client we have that exhibits this; same MI/refresh_token works fine from
az rest, browser, or raw curl.Asks
scope=(v2) instead ofresource=(v1) for MCP servers configured with custom OAuth scopes.AADSTS90023: Unsupported 'prompt' valueon fresh-session/mcp auth(likely same code path, different prompt parameter)./mcp refresh <server>command that re-runs the interactive flow without nuking other MCP caches would unblock us.Happy to provide HAR captures, additional trace IDs, or test patches.