Skip to content

feat: multi-provider OAuth pool — OpenAI, Cursor, Google AI Pro (#22) - #23

Closed
superdav42 wants to merge 3 commits into
mainfrom
feature/multi-provider-oauth-pool
Closed

superdav42 wants to merge 3 commits into
mainfrom
feature/multi-provider-oauth-pool

Conversation

@superdav42

@superdav42 superdav42 commented May 6, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • Adds multi-provider OAuth pool support — OpenAI ChatGPT/Codex, Cursor Pro, and Google AI Pro alongside the existing Anthropic Max pool.
  • Refactors the OAuthPool into a generic ProviderPool + PoolRegistry, with PoolManager retained as a back-compat facade for the Anthropic pool.
  • Adds per-provider REST routes under /anthropic-max-pool/v1/{provider}/… and a /providers index endpoint. Legacy Anthropic-only routes (/accounts, /authorize, /exchange, …) are preserved unchanged.
  • Connectors page now renders four cards with provider-specific badges and oauth-paste / manual-token form modes.

Resolves #22.

What this enables

Users with paid AI subscriptions (ChatGPT Plus/Pro, Codex, Cursor Pro, Google AI Pro/Ultra) can now use those plans from WordPress without per-token API billing — same UX as the existing Anthropic Max flow.

Provider Auth flow OAuth client Stored option key
Anthropic Max OAuth PKCE + paste code claude.ai/oauth anthropic_max_oauth_pool (unchanged)
OpenAI ChatGPT/Codex OAuth + paste code from localhost:1455/auth/callback auth.openai.com anthropic_max_oauth_pool_openai
Cursor Pro Manual token paste (no public OAuth) n/a anthropic_max_oauth_pool_cursor
Google AI Pro OAuth OOB + paste code accounts.google.com anthropic_max_oauth_pool_google

Architecture

File Role Lines
src/OAuthPool/ProviderConfig.php Per-provider OAuth constants (clientId, endpoints, scopes, redirect, UA, healthCheck) 291
src/OAuthPool/ProviderPool.php Generic pool: load/save, list, addAccount, addAccountManual (JWT-derived email), removeAccount, markRateLimited, refreshAccount, healthCheck, startOAuthFlow (PKCE), exchangeCode (handles code#state and full-URL paste), refreshTokens (provider-aware content-type) 809
src/OAuthPool/PoolRegistry.php Memoised pool factory + summary() for the /providers endpoint 84
src/OAuthPool/PoolManager.php Thin facade delegating to PoolRegistry::pool('anthropic'). Every public method, constant (OPTION_KEY, CLIENT_ID, TOKEN_ENDPOINT, AUTHORIZE_URL, REDIRECT_URI, SCOPES, USER_AGENT, REQUIRED_SCOPE, REMOVE_*), and signature used by 1.0/1.1 callers (AnthropicOAuthRequestAuthentication, provider-registration.php, models, REST handlers) is preserved. 233
inc/rest-api.php Per-provider routes + legacy Anthropic-only routes 698
js/connector.jsx Four registerConnector() cards driven by a PROVIDERS map; shared ProviderConnectorCard, OAuthAddForm, ManualTokenAddForm. Re-asserts registration on multiple ticks (workaround for WordPress/gutenberg#77116). 785
wp-multi-provider-test.mjs Playwright browser smoke test against host WordPress 97

Backward compatibility

  • No data migration. Anthropic uses the existing anthropic_max_oauth_pool option key; new providers use *_{openai,cursor,google} suffixed keys.
  • No API changes. All legacy /anthropic-max-pool/v1/{accounts,authorize,exchange,health,...} routes remain Anthropic-only with identical request/response shapes.
  • PoolManager is fully back-compat. Every public method (getActiveTokenWithEmail, addAccount, removeAccount, markRateLimited, refreshAccount, count, getRequiredScope, etc.) and constant is preserved.

Out of scope

AI Client SDK provider classes (*\Provider\OpenAiCodexProvider etc.) for OpenAI/Cursor/Google are explicitly not wired into WordPress\AiClient in this PR. Storage and rotation are fully implemented; SDK integration ships in a follow-up so this PR stays focused on pool infrastructure. Anthropic Max remains the only fully SDK-wired provider.

The OAuth callback handler bound to localhost:1455 (used by the OpenAI Codex CLI) is also out of scope — the WP server cannot bind that port; users paste the code from the redirected URL instead, mirroring how the upstream oauth-pool-add.sh shell helper works in headless environments.

Verification

REST smoke tests (host WP at http://wordpress.local:8080)

All authenticated cookie + nonce calls against the live plugin:

Endpoint Result
GET /providers 200 — returns all 4 providers with correct labels, counts, supportsOAuth flags
GET /openai/authorize 200 — https://auth.openai.com/oauth/authorize?...&redirect_uri=http%3A%2F%2Flocalhost%3A1455%2Fauth%2Fcallback
GET /google/authorize 200 — https://accounts.google.com/o/oauth2/v2/auth?...&redirect_uri=urn:ietf:wg:oauth:2.0:oob
GET /anthropic/authorize 200 — https://claude.ai/oauth/authorize?... (existing flow)
GET /cursor/authorize 400 oauth_unsupported (correct — Cursor uses manual token)
POST /cursor/manual (fake JWT) 200 — derives email from sub claim, persists
GET /cursor/accounts 200 — returns list with status, expiry, JWT-derived email
POST /cursor/accounts/remove 200 — count returns to 0
GET /accounts (legacy) 200 — Anthropic pool unchanged
GET /madeup/accounts 404 unknown_provider

Browser test

Playwright run against http://wordpress.local:8080/wp-admin/options-general.php?page=options-connectors-wp-admin after admin login:

[test] 3. Verify all four provider cards render
[test]    anthropic (Anthropic Max): OK
[test]    openai (OpenAI ChatGPT): OK
[test]    cursor (Cursor Pro): OK
[test]    google (Google AI Pro): OK
[test]    no plugin-related JS errors

All four cards render with provider-specific badges (MAX, GPT, CUR, GAI), descriptions, and Set up buttons.

Lint

  • php -l clean on all 4 new + 2 modified PHP files.
  • phpstan analyse src/OAuthPool/{ProviderConfig,ProviderPool,PoolRegistry}.php inc/rest-api.php → No errors. Repo-wide phpstan delta vs main: -2 errors (no regressions; remaining 235 are pre-existing AI Client SDK class-not-found, unrelated to this PR).
  • npm run build succeeds; build/connector.js is 15.4 KiB minified (was 12.5 KiB on main).

Recovery note

The wip: recover ... commit at the base of this branch reflects a recovery operation: the original worktree was deleted by an aidevops worktree-cleanup background job that misclassified the branch as merged. All file content was recovered from the OpenCode session database (.local/share/opencode/opencode.db part table) and matches the originally-tested versions byte-for-byte. The subsequent commits are the post-recovery version bump and test-fixture adjustment.


aidevops.sh v3.14.80 plugin for OpenCode v1.14.33 with claude-sonnet-4-6 spent 2d 12h on this as a headless worker.

Summary by CodeRabbit

  • New Features

    • Added multi-provider OAuth support for Anthropic Claude Max, OpenAI, Cursor Pro, and Google AI Pro
    • Introduced OAuth account pooling with automatic rotation and rate-limit handling
    • Added automatic token refresh functionality
    • Enabled manual token input for providers without OAuth support
    • Redesigned connector UI for managing multiple provider accounts
  • Documentation

    • Updated documentation and setup guides for multi-provider workflows

superdav42 added 3 commits May 6, 2026 10:46
Recovered after worktree was unexpectedly deleted. Original Write tool
calls extracted from /home/dave/.local/share/opencode/opencode.db part
table. Files restored:

- src/OAuthPool/ProviderConfig.php (new, 291 lines)
- src/OAuthPool/ProviderPool.php (new, 809 lines)
- src/OAuthPool/PoolRegistry.php (new, 84 lines)
- src/OAuthPool/PoolManager.php (refactored to facade, 233 lines)
- inc/rest-api.php (rewritten with per-provider routes, 698 lines)
- js/connector.jsx (rewritten with 4 cards, 785 lines)
- build/connector.js (rebuilt, 15.4 KiB)
- wp-multi-provider-test.mjs (new browser smoke test, 97 lines)

REST API smoke-tested end-to-end against host WP at wordpress.local:8080.
All 4 provider endpoints work (anthropic/openai/cursor/google), legacy
/accounts route preserved, error paths verified.
…8080

- Use Multisite Ultimate's custom login form selectors (input name=log/pwd).
- Use correct Gutenberg connectors page slug (options-connectors-wp-admin).
- Relax waitUntil and increase timeout for React-heavy admin page.
- Improve per-card setup button targeting using row-scoped locators.

Verified: all four provider cards (Anthropic Max, OpenAI ChatGPT/Codex,
Cursor Pro, Google AI Pro) render at
/wp-admin/options-general.php?page=options-connectors-wp-admin with the
correct labels, badges (MAX/GPT/CUR/GAI), and descriptions. No
plugin-related JS console errors.
Updates the plugin header, version constant, plugin description, and
readme.txt to reflect the multi-provider scope. The plugin now supports
four OAuth/manual-token providers (Anthropic Max, OpenAI, Cursor,
Google) instead of being Anthropic-only.

Stored option key conventions:
- anthropic_max_oauth_pool       (Anthropic — unchanged from 1.1.0)
- anthropic_max_oauth_pool_openai
- anthropic_max_oauth_pool_cursor
- anthropic_max_oauth_pool_google

Resolves #22.
@coderabbitai

coderabbitai Bot commented May 6, 2026 •

Copy link
Copy Markdown

Caution

Review failed

Failed to post review comments

📝 Walkthrough

Walkthrough

The PR transforms the plugin from a single-provider (Anthropic Max) OAuth integration into a multi-provider OAuth pool supporting Anthropic, OpenAI, Cursor Pro, and Google AI Pro. New infrastructure classes (ProviderConfig, PoolRegistry, ProviderPool) manage per-provider account pools with independent token refresh and rate-limit handling. REST API routes are restructured to serve per-provider endpoints while maintaining legacy Anthropic-only compatibility. The connector UI is refactored to dynamically render provider cards from a centralized registry.

Changes

Multi-Provider OAuth Pool Architecture

Layer / File(s) Summary
Provider Configuration & Registry
src/OAuthPool/ProviderConfig.php, src/OAuthPool/PoolRegistry.php
Introduces ProviderConfig with OAuth endpoints/scopes/metadata for four providers (anthropic, openai, cursor, google) and PoolRegistry for memoizing per-provider pool instances with aggregation support.
Core Pool Implementation
src/OAuthPool/ProviderPool.php
New provider-agnostic pool class manages account storage, token refresh, PKCE OAuth flows, manual token entry, cooldown/rate-limit handling, and health checks per provider.
PoolManager Refactoring
src/OAuthPool/PoolManager.php
Rewritten as a lightweight facade over ProviderPool; adds constants for backward compatibility and delegates account/token operations to an underlying pool retrieved via PoolRegistry.
REST API Multi-Provider Routes
inc/rest-api.php
Restructured to register per-provider endpoints (/anthropic-max-pool/v1/{provider}/...) alongside legacy Anthropic-only routes; adds resolve_pool, per-provider handlers (list accounts, OAuth start/exchange, manual add, remove, refresh, health), and legacy wrappers.
Frontend Connector Refactoring
js/connector.jsx
Refactored from hardcoded Anthropic card to dynamic provider-agnostic UI; introduces ProviderLogo and ManualTokenAddForm components, reuses OAuthAddForm with provider-driven labels/endpoints, and implements dynamic registration via ProviderConnectorCard and centralized REST_NS routing.
Compiled Output & Metadata
build/connector.js, plugin.php
Compiled output generated from refactored jsx; plugin header updated to describe multi-provider support and version bumped to 1.2.0.
Documentation & E2E Testing
readme.txt, wp-multi-provider-test.mjs
Readme expanded to document four provider cards, REST routes, and pool features in version 1.2.0 changelog; new Playwright test script verifies provider card rendering, OAuth/manual flows, and error handling.

Sequence Diagram

sequenceDiagram
    actor Admin as WordPress Admin
    participant UI as Connector UI<br/>(js/connector.jsx)
    participant REST as REST API<br/>(inc/rest-api.php)
    participant Reg as PoolRegistry
    participant Cfg as ProviderConfig
    participant Pool as ProviderPool
    participant WPOpt as WordPress Options
    
    Admin->>UI: Click Settings > Connectors
    UI->>UI: Load Provider Config for all providers
    UI->>UI: Register 4 provider cards dynamically
    Admin->>UI: Click "Add Account" for OpenAI
    
    UI->>REST: POST /openai/authorize?login_hint=user@example.com
    REST->>Reg: resolve_pool('openai')
    Reg->>Cfg: ProviderConfig::forId('openai')
    Cfg->>Reg: Return openai config
    Reg->>Pool: Create ProviderPool(openai_config)
    Pool->>WPOpt: Load openai accounts pool
    REST->>REST: Generate PKCE verifier/challenge
    REST-->>UI: Return {authorize_url, state}
    
    UI->>Admin: Display OAuth login link
    Admin->>Admin: Complete login on auth.openai.com
    Admin->>UI: Paste code + state
    
    UI->>REST: POST /openai/exchange {code, state, email}
    REST->>Reg: resolve_pool('openai')
    Reg->>Pool: Call exchangeCode(...)
    Pool->>Pool: POST token request to openai token endpoint
    Pool->>WPOpt: Save tokens to openai pool
    REST-->>UI: Return {access_token, refresh_token}
    
    UI->>UI: Render account in list (OpenAI provider)
    
    Admin->>UI: Click "Add Account" for Cursor
    UI->>UI: Switch to ManualTokenAddForm
    Admin->>UI: Paste access & refresh tokens
    
    UI->>REST: POST /cursor/manual {access_token, refresh_token, email}
    REST->>Reg: resolve_pool('cursor')
    Reg->>Pool: Call addAccountManual(...)
    Pool->>WPOpt: Save manual tokens to cursor pool
    REST-->>UI: Return success
    
    UI->>UI: Render account list (both OpenAI and Cursor accounts isolated)
Loading

Estimated Code Review Effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly Related PRs

Poem

🐰 Four providers now dance in a ring,
OAuth pools for each provider thing—
Anthropic, OpenAI, Cursor, Google bright,
Rotation and refresh keep tokens just right!
🌈 The pool manager hops with delight.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 46.15% 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
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title clearly and concisely summarizes the primary change: adding multi-provider OAuth pool support for OpenAI, Cursor, and Google AI Pro alongside the existing Anthropic integration.
Linked Issues check ✅ Passed The PR fulfills all core coding requirements from issue #22: provider-aware sub-pools with ProviderPool/PoolRegistry/ProviderConfig, per-provider OAuth flows (PKCE, OOB paste-code, manual token), REST API per-provider routes, four connector cards with provider-specific flows, and isolated storage per provider.
Out of Scope Changes check ✅ Passed All changes align with issue #22 scope; version bump, readme updates, and Playwright smoke test are supporting artifacts. No unrelated refactoring or feature creep detected.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/multi-provider-oauth-pool

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 PHPStan (2.1.54)

PHPStan was skipped because the config uses disallowed bootstrapFiles, bootstrapFile, or includes directives.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@superdav42 superdav42 closed this May 7, 2026
@superdav42
superdav42 deleted the feature/multi-provider-oauth-pool branch May 7, 2026 17:11
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.

feature: support OpenAI Codex, Cursor Pro, and Google AI Pro OAuth plans

1 participant