Forum Discussion
New AI Foundry not sending refresh tokens to MCP (401 after access token expiration)
Hello,
I can confirm this exact issue in a different environment.
Our setup:
- MCP server hosted on Azure App Service (not Azure Function)
- Authentication: OAuth Identity Passthrough configured in AI Foundry
- App Registration: Single tenant, Web redirect to global.consent.azure-apim.net, client secret set
- Token URL, Auth URL, and Refresh URL all correctly pointing to https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token
- Scopes include offline_access
- Connection is called via the Responses API (POST /openai/responses) in Agent Reference Mode from a custom Node.js backend
Observed behavior:
- Initial OAuth consent works perfectly — user authenticates, MCP tools execute successfully
- After approximately 60–90 minutes (standard access token lifetime), all MCP calls fail
- The API returns response.mcp_list_tools.failed followed by a new oauth_consent_request
- After manually re-authenticating (clicking "Allow" in the consent popup), tools work again for another ~60–90 minutes
What we verified:
- Refresh URL is correctly configured (same as token URL, which is standard for Entra ID)
- Client secret is active and valid (expires 2028)
- offline_access is included in scopes
- The initial token exchange should provide both access_token and refresh_token (per OBO flow documentation)
Our conclusion aligns with yours: The API Hub stores the refresh token but never uses it to acquire a new access token when the original expires. This forces re-authentication every ~1 hour, making long-lived agent sessions impractical.
Workaround we implemented:
When our backend detects mcp_auth_expired (via SSE error event), we automatically create a new conversation and present the consent popup to the user. After re-authentication, we continue the original request in the fresh conversation. This works but requires user interaction every hour.
We have tested with two separate MCP connections (created weeks apart) — the behavior is identical on both. This is clearly a platform-level issue with the API Hub's token lifecycle management.