Skip to content

refactor: migrate OAuth flow state/PKCE fields from oauth_configs to new mcp_oauth_flows table - #5709

Merged
Pratham-Mishra04 merged 1 commit into
devfrom
07-29-feat_unify_oauth_flow_storage_into_tablemcpoauthflow
Aug 8, 2026
Merged

refactor: migrate OAuth flow state/PKCE fields from oauth_configs to new mcp_oauth_flows table#5709
Pratham-Mishra04 merged 1 commit into
devfrom
07-29-feat_unify_oauth_flow_storage_into_tablemcpoauthflow

Conversation

@Pratham-Mishra04

Copy link
Copy Markdown
Collaborator

Summary

Introduces mcp_oauth_flows as a dedicated table for in-flight OAuth authorize attempts, replacing the dual-purpose oauth_user_sessions table and removing CSRF/PKCE columns (state, code_verifier, code_challenge, expires_at) from oauth_configs. The new TableMCPOauthFlow covers all flow kinds — per-identity (user, vk, session) and admin-mode (admin) alike — while TableOauthConfig becomes a pure, durable credential template.

Changes

  • New TableMCPOauthFlow struct and mcp_oauth_flows table: Carries state, code_verifier, redirect_uri, expires_at, and flow_mode for a single authorize attempt. CodeVerifier is encrypted via BeforeSave/AfterFind hooks, matching the behavior previously on TableOauthConfig.
  • Two new migrations:
    • create_mcp_oauth_flows_table: Creates mcp_oauth_flows and backfills from oauth_user_sessions via INSERT...SELECT. The unique index on state is created after the backfill to avoid ordering issues.
    • drop_oauth_config_pkce_columns: Drops state, code_verifier, code_challenge, and expires_at from oauth_configs. These columns were NOT NULL at the DB level and would have broken future INSERTs once the Go struct stopped setting them.
  • TableOauthConfig simplified: PKCE/CSRF fields removed from the struct, BeforeSave/AfterFind hooks updated to only encrypt/decrypt client_secret. The EncryptionStatus is now set only when client_secret is present.
  • InitiateOAuthFlow updated: Creates the oauth_configs row and a flow_mode='admin' flow row atomically in a single transaction to prevent orphaned config rows on partial failure.
  • CompleteOAuthFlow updated: Claims the admin-mode flow row via the new ClaimOauthFlowByState (scoped to flow_mode='admin'), reads CodeVerifier and RedirectURI from the flow row, and deletes the flow row on completion.
  • New ClaimOauthFlowByState method: Admin-mode counterpart to ClaimOauthUserSessionByState. The two methods partition mcp_oauth_flows by flow_mode so a given state token can only be claimed by one of them.
  • New GetOauthUserSessionByState method: Non-mutating lookup by state for any flow_mode or status, used by callback error handling to classify and mark a flow failed without consuming it.
  • GetOauthConfigByState removed: No longer needed; oauth_configs no longer has a state column.
  • GetPendingMCPClientByState removed: Callers now use GetPendingMCPClient directly after resolving the config ID from the flow row.
  • handleCallbackError updated: Classifies admin vs. per-user flows via flow.FlowMode on a single mcp_oauth_flows lookup instead of the old two-step oauth_configs-then-assume-per-user inference.
  • ListPendingOauthUserSessions updated: Now queries mcp_oauth_flows and explicitly excludes flow_mode='admin' rows, mirroring ListOauthUserTokens' auth_mode='shared' exclusion.
  • DeleteExpiredOauthUserSessions updated: Targets mcp_oauth_flows; deliberately unfiltered by flow_mode since expiry-based sweeping is safe for all flow kinds.
  • Cascade deletes updated: DeleteMCPClientConfig and DeleteVirtualKey now delete from mcp_oauth_flows instead of oauth_user_sessions.
  • reconcileVKDirectTokensDB and readVKsHoldingOauthCredsForMCP updated: Reference mcp_oauth_flows with a flow_mode='vk' defense-in-depth filter.
  • migrationWidenEncryptedVarcharColumns guarded: The ALTER COLUMN code_verifier statement is now conditional on the column existing, since fresh installs after drop_oauth_config_pkce_columns ships will never have it on oauth_configs.
  • TableOauthUserSession marked deprecated: Retained only so the backfill migration can reference its table via GORM; flagged for removal in the next major version.
  • Performance test added: TestMigrationCreateMCPOauthFlowsTablePerf seeds ~1,000,000 rows into oauth_user_sessions and measures migrationCreateMCPOauthFlowsTable against both SQLite and Postgres, gated behind BIFROST_RUN_MIGRATION_PERF_TESTS=1.
  • Encryption tests updated: TestTableOauthConfig_EncryptDecrypt and related tests drop code_verifier/state/expires_at assertions; new TestTableMCPOauthFlow_EncryptDecrypt and TestTableMCPOauthFlow_EncryptionDisabled_StoresPlaintext cover the equivalent round-trips on the new table.

Type of change

  • Bug fix
  • Feature
  • Refactor
  • Documentation
  • Chore/CI

Affected areas

  • Core (Go)
  • Transports (HTTP)
  • Providers/Integrations
  • Plugins
  • UI (React)
  • Docs

How to test

go test ./framework/configstore/... ./framework/oauth2/... ./transports/bifrost-http/...

To run the migration performance test against a live Postgres instance:

BIFROST_RUN_MIGRATION_PERF_TESTS=1 go test ./framework/configstore/... -run TestMigrationCreateMCPOauthFlowsTablePerf -v

For an existing deployment, apply the two new migrations (create_mcp_oauth_flows_table, drop_oauth_config_pkce_columns) and verify:

  • mcp_oauth_flows exists and contains all rows previously in oauth_user_sessions.
  • oauth_configs no longer has state, code_verifier, code_challenge, or expires_at columns.
  • New OAuth flows (admin and per-user) complete end-to-end without error.
  • Expired flow cleanup (DeleteExpiredOauthUserSessions) removes rows from mcp_oauth_flows.

Breaking changes

  • Yes
  • No

GetOauthConfigByState and GetPendingMCPClientByState are removed from the ConfigStore interface. Any external implementation of ConfigStore must add GetOauthUserSessionByState and ClaimOauthFlowByState, and remove the deleted methods. The oauth_configs table loses four columns; any direct SQL queries against those columns will fail after the migration runs.

Security considerations

  • CSRF state tokens and PKCE verifiers now live exclusively on mcp_oauth_flows, which has a unique index on state and a 15-minute expires_at. The atomic claim-by-state pattern (pending → claiming) is preserved and extended to admin-mode flows via ClaimOauthFlowByState, preventing duplicate callback processing.
  • The config row and its flow row are created in a single transaction in InitiateOAuthFlow, eliminating the window where a committed config row with no corresponding flow row could be exploited or leak state.
  • CodeVerifier encryption is unchanged in behavior; it has moved from TableOauthConfig to TableMCPOauthFlow.

Checklist

  • I read docs/contributing/README.md and followed the guidelines
  • I added/updated tests where appropriate
  • I updated documentation where needed
  • I verified builds succeed (Go and UI)
  • I verified the CI pipeline passes locally if applicable

Pratham-Mishra04 commented Jul 30, 2026

Copy link
Copy Markdown
Collaborator Author

This stack of pull requests is managed by Graphite. Learn more about stacking.

@CLAassistant

Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

@coderabbitai

coderabbitai Bot commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Summary by CodeRabbit

  • Enhancements

    • Improved OAuth authorization for user, virtual-key, and administrator sign-ins.
    • Improved concurrent authorization handling with more reliable state tracking and callback processing.
    • Added automatic cleanup for temporary authorization data after successful or failed flows.
    • Improved security by encrypting sensitive authorization data and separating temporary flow details from saved configuration.
  • Bug Fixes

    • Prevented incomplete OAuth configurations from being processed during encryption updates.
    • Improved handling of failed callbacks and pending authorization flows.
    • Removed the obsolete OAuth expiration field from status responses.

Walkthrough

OAuth configuration rows now store reusable credentials. Transient state and PKCE data move to mcp_oauth_flows. Migrations, storage APIs, OAuth callbacks, handlers, public schemas, and tests now use the unified flow model.

Changes

OAuth flow persistence

Layer / File(s) Summary
Flow schema and encryption contract
framework/configstore/tables/mcpoauth2.go, framework/configstore/encryption.go, framework/configstore/*_test.go
Adds TableMCPOauthFlow. Removes flow-specific fields from TableOauthConfig. Encrypts client secrets and flow verifiers in their respective records.
Migration pipeline and performance
framework/configstore/migrations.go, framework/configstore/migrations_perf_test.go
Creates and backfills mcp_oauth_flows, removes obsolete configuration columns, handles SQLite and PostgreSQL cases, and measures migration performance with one million rows.
Storage layer APIs
framework/configstore/store.go, framework/configstore/rdb.go, framework/configstore/rdb_test.go
Uses unified flow records for CRUD, state lookup, atomic claims, pending-flow filtering, token cleanup, deletion, and reconciliation.
OAuth callback flow and token exchange
framework/oauth2/main.go, framework/oauth2/sync_test.go
Creates configuration and admin flow rows transactionally. Claims flows by state, uses flow-specific PKCE data, replaces shared tokens transactionally, and cleans up terminal flows.
Transport handlers and public contracts
transports/bifrost-http/handlers/*, transports/bifrost-http/lib/config_test.go, docs/openapi/*, ui/lib/types/mcp.ts
Updates handlers and mocks for unified flows. Removes configuration-level expires_at from API schemas and UI types.

Estimated code review effort: 5 (Critical) | ~90+ minutes

Sequence Diagram(s)

sequenceDiagram
  participant OAuthHandler
  participant ConfigStore
  participant mcp_oauth_flows
  participant OAuthProvider
  OAuthHandler->>ConfigStore: create config and admin flow transactionally
  ConfigStore->>mcp_oauth_flows: persist state and PKCE data
  OAuthProvider-->>OAuthHandler: return callback state and code
  OAuthHandler->>ConfigStore: claim flow by state
  OAuthHandler->>OAuthProvider: exchange code with flow verifier
  OAuthHandler->>ConfigStore: replace shared token transactionally
  ConfigStore->>mcp_oauth_flows: delete terminal flow
Loading

Possibly related PRs

Suggested reviewers: akshaydeo, danpiths, bearts

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 75.68% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description check ✅ Passed The description follows the template and provides complete details about changes, testing, breaking changes, security, and affected areas.
Title check ✅ Passed The title clearly and concisely summarizes the main OAuth flow state and PKCE migration.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch 07-29-feat_unify_oauth_flow_storage_into_tablemcpoauthflow

Comment @coderabbitai help to get the list of available commands.

@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

@Pratham-Mishra04
Pratham-Mishra04 force-pushed the 07-28-feat_unify_shared_and_per-user_mcp_oauth_token_storage_into_tablemcpoauthtoken branch from 7949fe6 to fb096cd Compare August 8, 2026 08:43
@Pratham-Mishra04
Pratham-Mishra04 force-pushed the 07-29-feat_unify_oauth_flow_storage_into_tablemcpoauthflow branch from 83be929 to f2c9723 Compare August 8, 2026 08:43

Pratham-Mishra04 commented Aug 8, 2026

Copy link
Copy Markdown
Collaborator Author

Merge activity

  • Aug 8, 8:47 AM UTC: A user started a stack merge that includes this pull request via Graphite.
  • Aug 8, 9:04 AM UTC: Graphite rebased this pull request as part of a merge.
  • Aug 8, 9:04 AM UTC: @Pratham-Mishra04 merged this pull request with Graphite.

@Pratham-Mishra04
Pratham-Mishra04 changed the base branch from 07-28-feat_unify_shared_and_per-user_mcp_oauth_token_storage_into_tablemcpoauthtoken to graphite-base/5709 August 8, 2026 09:00
@Pratham-Mishra04
Pratham-Mishra04 changed the base branch from graphite-base/5709 to dev August 8, 2026 09:03
@Pratham-Mishra04
Pratham-Mishra04 dismissed coderabbitai[bot]’s stale review August 8, 2026 09:03

The base branch was changed.

@Pratham-Mishra04
Pratham-Mishra04 requested a review from a team as a code owner August 8, 2026 09:03
@Pratham-Mishra04
Pratham-Mishra04 force-pushed the 07-29-feat_unify_oauth_flow_storage_into_tablemcpoauthflow branch from f2c9723 to e43d331 Compare August 8, 2026 09:03
@Pratham-Mishra04
Pratham-Mishra04 merged commit 094e0cc into dev Aug 8, 2026
14 of 15 checks passed
@Pratham-Mishra04
Pratham-Mishra04 deleted the 07-29-feat_unify_oauth_flow_storage_into_tablemcpoauthflow branch August 8, 2026 09:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants