feat: handle revoked OAuth grants for MCP servers gracefully - #27264
Conversation
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 3cfe876d0e
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
@codex review |
|
Codex Review: Didn't find any major issues. Nice work! Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
|
@codex review |
|
Codex Review: Didn't find any major issues. Chef's kiss. Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
|
@codex review |
|
Codex Review: Didn't find any major issues. Another round soon, please! Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
4b987cf to
03ac55c
Compare
|
@codex review |
|
Codex Review: Didn't find any major issues. 👍 Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
Closes CODAGT-792.
When a user revokes an upstream OAuth grant for an MCP server used by Coder Agents, Coder kept treating the cached token as valid:
invalid_grantrefresh failures were logged and swallowed, the dead bearer token kept being attached, the list endpoints re-attempted the refresh on every call, and the UI kept showing the server as authenticated.Changes
Backend, mirroring the
external_auth_linksprior art:mcp_server_user_tokens.oauth_refresh_failure_reason.UpsertMCPServerUserTokenclears it, so completing the OAuth flow again recovers the row.MarkMCPServerUserTokenRefreshFailurequery records the failure and clears all token material, guarded by anupdated_atoptimistic lock so a stale failure never clobbers a concurrently refreshed token (on a lock miss the winner's row is used).mcpclient.IsPermanentRefreshErrorclassifies*oauth2.RetrieveErrorcodes: onlyinvalid_grantandbad_refresh_tokenare permanent. Client/config errors (invalid_client,unauthorized_client, ...) stay transient for the user row since reconnecting cannot fix them.buildAuthHeadersno longer attaches an Authorization header for failed tokens, so chat degrades by omitting that server's tools instead of sending a dead bearer.API and UI:
auth_connected: false, so the existing "Auth" button and "Not authenticated" tooltip appear and the user re-runs the same OAuth flow to recover. An earlier revision added anauth_statusenum (connected/not_connected/reconnect_required) with a dedicated "Reconnect" button; it was collapsed to keep the API minimal since both states lead to the identical re-auth action.Out of scope (follow-up): typed 401-on-connect detection and forced refresh. mcp-go exposes no stable typed 401 signal in the static-header path, so a revocation while the access token still looks valid locally stays undetected until expiry triggers a refresh.
Testing
invalid_grant: revoked grant detected on refresh and persisted once (no repeated IdP calls), chat with the revoked server selected completes with the server's tools omitted, and re-auth restores the connected state.