Skip to content

fix(core): coordinate OAuth credential refreshes - #50760

Closed
hcrosse wants to merge 7 commits into
anomalyco:devfrom
hcrosse:oauth-refresh-lock
Closed

hcrosse wants to merge 7 commits into
anomalyco:devfrom
hcrosse:oauth-refresh-lock

Conversation

@hcrosse

@hcrosse hcrosse commented Sep 22, 2026 •

Copy link
Copy Markdown

Issue for this PR

Closes #50759

Related to #34520, which tracks the separate MCP OAuth path.

Type of change

  • Bug fix
  • New feature
  • Refactor / code improvement
  • Documentation

What does this PR do?

Coordinates OAuth credential refreshes across locations and processes that share a credential database. The refresh path now rereads the credential while holding a file lock, uses a 30-second expiry margin for short-lived tokens, persists rotated credentials with a guarded update, and blocks replay after an exchange has an uncertain outcome.

This prevents a five-minute token from refreshing immediately and prevents concurrent callers from spending the same rotating refresh token twice.

How did you verify your code works?

  • The integration and credential tests cover fresh five-minute tokens, concurrent locations and processes, refresh-token rotation, later refreshes from persisted credentials, concurrent replacement and removal, cancellation, failure, timeout, and independent credentials.
  • Core typechecking, repository lint, formatting, and diff checks pass.
  • The full core suite completed with 5,457 passing and 41 skipped tests. Eight existing environment and Bash-shell tests fail independently of this change; the OAuth refresh tests pass in the full run.
  • I ran a dev build with my internal provider plugin and this fixes the OAuth issue and allowed me to view and prompt models successfully.

Screenshots / recordings

Not applicable.

Checklist

  • I have tested my changes locally
  • I have not included unrelated changes in this PR

@github-actions

Copy link
Copy Markdown
Contributor

Thanks for your contribution!

This PR doesn't have a linked issue. All PRs must reference an existing issue.

Please:

  1. Open an issue describing the bug/feature (if one doesn't exist)
  2. Add Fixes #<number> or Closes #<number> to this PR description

See CONTRIBUTING.md for details.

@hcrosse hcrosse Sep 22, 2026 •

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I pulled this out since it was essentially doubling integration.test.ts's line count, but not sure if this is better organizationally - please lmk!

@hcrosse
hcrosse marked this pull request as ready for review September 22, 2026 23:43
Copilot AI balanced review requested due to automatic review settings October 2, 2026 15:49

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

File locking currently affects all stored credential resolutions, causing unnecessary latency and filesystem dependency for non-refresh paths.

Review effort: Balanced
Findings: 1 Medium severity

Open (1)
What changed in this PR

Coordinates OAuth credential refreshes across locations and processes sharing credential storage.

Changes:

  • Adds file-lock-based refresh coordination, expiry margin, timeout, and failed-refresh replay protection.
  • Adds compare-and-swap credential updates to prevent stale overwrites.
  • Adds comprehensive concurrency, rotation, cancellation, and process-level tests.
File Description
packages/​core/​src/​integration.ts Coordinates OAuth refresh operations.
packages/​core/​src/​credential.ts Adds guarded credential-value updates.
packages/​core/​src/​database/​database.ts Exposes the backing database path.
packages/​core/​test/​integration-refresh.test.ts Tests refresh coordination and failure scenarios.
packages/​core/​test/​credential.test.ts Tests guarded updates.
packages/​core/​test/​integration.test.ts Updates integration test layers and mocks.
packages/​core/​test/​mcp-oauth.test.ts Updates the credential mock interface.
packages/​core/​test/​config/​config.test.ts Updates configuration-test mocks.
packages/​core/​test/​fixture/​config-nodes.ts Updates shared credential fixtures.
packages/​core/​test/​fixture/​oauth-refresh.ts Adds a refresh endpoint fixture.
packages/​core/​test/​fixture/​integration-refresh-worker.ts Adds cross-process refresh workers.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +715 to +717
const lockKey = `credential:${connection.id}`
return yield* flock
.withLock(
@thdxr
thdxr changed the base branch from v2 to dev October 10, 2026 19:14
@github-actions

Copy link
Copy Markdown
Contributor

Automated PR Cleanup

Thank you for contributing to opencode.

Due to the high volume of PRs from users and AI agents, we periodically close older PRs using automated criteria so maintainers can focus review time on the most active and community-supported contributions.

This PR was closed because it matched the following cleanup criteria:

  • The PR was created more than 1 month ago
  • The PR had fewer than 2 positive reactions
  • Positive reactions are counted as thumbs-up, heart, celebration, or rocket reactions on the PR

PRs created within the last month are not affected by this cleanup.

If you believe this PR was closed incorrectly, or if you are still actively working on it, please leave a comment explaining why it should be reopened. A maintainer can review and reopen it if appropriate.

Thanks again for taking the time to contribute.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

V2 provider OAuth refresh races across locations and processes

2 participants