Fix ensureCredential dropping a verified oauth_token reconnect - #489
Merged
Merged
Conversation
Reproduces CL-7236: an interactive MCP OAuth reconnect passes credentialVerified: true after completing a fresh exchange, but a name conflict against a still-active existing row currently skips rotation entirely -- zero PATCH calls, and the stale credential id is returned as if the reconnect succeeded.
…nect The oauth_token rotate-on-conflict check only looked at the existing row's status, so a caller passing verified: true (an interactive MCP OAuth reconnect that just completed a fresh, probe-confirmed exchange) had that signal silently ignored whenever the stored row hadn't yet gone stale. The freshly minted token was dropped and the stale credential id returned as if the reconnect had worked. Rotate whenever the row is stale OR the caller marks the token verified, mirroring how the api_key branch already uses verified.
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.
Summary
ensureCredential's rotate-on-409-conflict check foroauth_tokencredentials only looked at the existing row'sstatus. The interactive MCP OAuth reconnect route (packages/connections/src/mcp-oauth-routes.ts) already passesverified: trueafter completing a fresh, probe-confirmed OAuth exchange -- but that signal was silently ignored foroauth_token, so reconnecting an integration whose stored credential was stillactive(not yet expired) dropped the freshly minted token entirely: zero PATCH calls, and the stale row's id returned as if the reconnect had worked.Fix: rotate whenever the existing row is stale (
status !== "active", unchanged) or the caller marks the tokenverified-- mirroring how theapi_keybranch already usesverified. A plainworkbench seednever setsverifiedon anoauth_tokencredential, so a routine unverified re-seed of a still-active row keeps skipping exactly as before.Self-review (Greybeard/Critique unavailable this session -- see note)
activestatus still rotates,activenow rotates too when verified. The four credential statuses (active,expired,revoked,error) are covered: any non-activestatus rotates unconditionally (unchanged from before), andactivenow also rotates whenargs.verified === true.verified: truefor anoauth_tokencredential has already proven the secret before callingensureCredential: the MCP OAuth route only reaches it afterprobe(...)confirms the exchanged token actually works (redirecting with an error first otherwise), and the genericpersistConnectorCredentialpath (packages/connections/src/persist-credential.ts) documents the same invariant -- "the credential is already proven by the OAuth exchange itself."oauth_tokenis anactiverow withverifiedunset orfalse-- the intentional, correct "idempotent re-seed with an unchanged token" case the acceptance criteria call out to preserve. Every "a genuinely new, verified token arrived" case now rotates.Note
Greybeard and Critique subagent review were unavailable for this change (session-wide concurrent-subagent limit hit repeatedly); the self-review above substitutes.
Test plan
WORKBENCH_CHECK_CONCURRENCY=2 WORKBENCH_CHECK_SINCE=origin/main bun run typecheck-- cleanWORKBENCH_CHECK_CONCURRENCY=2 WORKBENCH_CHECK_SINCE=origin/main bun run test(narrowed per-package runner;scripts/*.test.tsrun separately without the concurrency env var, which otherwise collides with its own concurrency-default assertion) -- all packages touched by this change pass;@corbits/chat-uiand@corbits/routinesfailures under the capped parallel run were confirmed to be resource-contention flakes unrelated to this change (both pass standalone, 817/817 and 267/267)bun run lint-- 0 errors (8 pre-existing warnings, none in touched files)bun run check:structural-- cleanpackages/hub-client/test/seed.test.ts-- "a name conflict on a verified oauth_token reconnect rotates the still-active row", confirmed red against the pre-fix code (0 PATCH calls) and green after the fix