Multi-account OAuth rotation plugin for OpenCode with a local dashboard, force mode, weighted settings, limits probing, and reliability hardening.
README.md-> primary operator and developer documentation for current behavior.docs/ADMIN_MERGE_BRIEF.md-> concise upstream/admin review summary.docs/PHASE_H_VALIDATION.md-> final validation report (current readiness reference).codextesting.md-> live/manual testing runbook.docs/README.md-> full docs index with authoritative vs historical references.
- Rotates requests across multiple ChatGPT/Codex OAuth accounts.
- Keeps a local account store with migration, validation, and atomic writes.
- Provides a localhost dashboard to manage accounts and limits.
- Supports force mode (pin one alias), account enable/disable, and re-auth.
- Supports settings-driven rotation strategy (
round-robin,least-used,random,weighted-round-robin). - Probes limits safely and keeps authoritative data quality rules.
- Gates non-core Antigravity features behind a feature flag.
- Core phases A-G are implemented in this workspace.
- Validation scripts are available for: unit, integration, web-headless, failure, stress, sandbox, soak.
- Web hardening fixes are in place:
- localhost-only bind enforcement
- malformed JSON returns deterministic
400without process crash - dashboard client script parse issue fixed
- Rate-limit handling sleeps an alias until reset when reset timing is known (
Retry-After, rate-limit window reset, or parsed provider reset text), instead of retrying that alias immediately. - Force mode is strict: when enabled, requests stay pinned to the forced alias and do not silently fall back to other aliases.
- Rotation strategy control is shown next to Force Mode in the dashboard.
- Strategy changes from dashboard settings are applied to runtime selection logic (not just persisted state/UI display).
- Force Mode and strategy interaction is explicit:
- while Force Mode is ON, strategy changes are saved
- saved strategy becomes active when Force Mode is turned OFF
- Dashboard controls include mouseover help text for Force Mode and rotation strategy definitions.
- Account enable/disable toggle is authoritative for eligibility in rotation.
round-robin-> cycle through healthy enabled accounts in order.least-used-> prefer the healthy enabled account with the lowest usage count.random-> pick randomly from healthy enabled accounts.weighted-round-robin-> split traffic by configured account weights (example:0.70/0.20/0.10≈70%/20%/10%).- Force Mode precedence -> when Force Mode is ON, strategy is paused; strategy changes are saved and become active when Force Mode is OFF.
src/-> TypeScript sourcedist/-> compiled output (tscgenerated)tests/unit/-> unit teststests/integration/-> integration teststests/web-headless/-> headless UI smoke teststests/failure/-> failure-injection teststests/stress/-> stress/concurrency teststests/sandbox/-> sandbox isolation teststests/soak/-> soak scaffoldingdocs/-> QA and phase documentation (seedocs/README.mdfor canonical/historical split)IMPLEMENTATION_PLAN.md-> full plan and contractsTEST_EXECUTION_PLAN.md-> required test order and gatescodextesting.md-> live testing TODO for Codex CLI sessionsauto-login/-> Python script for bulk Outlook-based OAuth login
- Node.js 20+
- npm
- OpenCode CLI
- ChatGPT/Codex OAuth accounts
In your OpenCode config (~/.config/opencode/opencode.json):
{
"plugin": ["github:guard22/opencode-multi-auth-codex"]
}git clone https://github.com/guard22/opencode-multi-auth-codex.git
cd opencode-multi-auth-codex
npm ci
npm run build# Add accounts
opencode-multi-auth add personal
opencode-multi-auth add work
# Check status
opencode-multi-auth status
# Start dashboard
opencode-multi-auth web --host 127.0.0.1 --port 3434Open http://127.0.0.1:3434.
The auto-login/ directory contains a standalone Python script that automates the full OAuth login flow for multiple Outlook-based ChatGPT accounts. Instead of manually running opencode-multi-auth add and clicking through the browser for each account, the script handles everything:
- Opens OpenAI auth page
- Enters email, requests a one-time login code
- Logs into Outlook Web to read the verification code
- Enters the code, clicks through the consent page
- Captures the OAuth tokens and writes them directly into the plugin store
- Python 3.9+
- Playwright (Python):
pip install playwright playwright install chromium
- Outlook.com accounts linked to ChatGPT (the script reads OTP codes from Outlook Web)
-
Copy the example credentials file:
cp auto-login/credentials.example.json auto-login/credentials.json
-
Edit
auto-login/credentials.jsonwith your real accounts:{ "defaults": { "chatgpt_password": "SharedPasswordIfAny" }, "accounts": [ { "id": "acc-1", "email": "your-email@outlook.com", "outlook_password": "your-outlook-password", "chatgpt_password": "your-chatgpt-password", "enabled": true } ] }defaults.chatgpt_passwordis used when an account doesn't specify its own.outlook_passwordis required for reading OTP codes from Outlook inbox.- Set
enabled: falseto skip an account without removing it.
# Check which accounts need login
python3 auto-login/auto_login.py --check
# Login all enabled accounts (headless)
python3 auto-login/auto_login.py
# Login a specific account by index
python3 auto-login/auto_login.py --account 0
# Login a specific account by email
python3 auto-login/auto_login.py --email user@outlook.com
# Run with visible browser (for debugging)
python3 auto-login/auto_login.py --visibleOpenAI Auth Outlook Web Local Server
| | |
| 1. Enter email | |
| 2. Click "one-time code" | |
| ----sends OTP email-------> | |
| | 3. Login to Outlook |
| | 4. Read OTP from inbox |
| 5. Enter OTP code | |
| 6. Click Continue (consent) | |
| ----redirect callback-----> | ----code via HTTP GET----> |
| | | 7. Capture code
| | | 8. Exchange for tokens
| | | 9. Write to plugin store
The script generates a PKCE challenge identical to the plugin's own OAuth flow, starts a local HTTP server on port 1455 to capture the callback, and writes tokens in the exact v2 store format the plugin expects.
Outlook login often shows interstitial pages after password entry:
| Page | Handled by |
|---|---|
| "Stay signed in?" | Auto-clicks "Yes" |
| "Let's protect your account" | Auto-clicks "Skip for now" |
FIDO/Passkey creation (/fido/create) |
Auto-clicks "Not now" / "Cancel" |
| Any other blocker | Force-navigates to inbox |
--visiblemode shows the browser so you can see exactly where the flow gets stuck.- Debug screenshots are saved as
auto-login/debug_<user>_<step>.pngon failure. - SSL errors on macOS: the script uses
ssl._create_unverified_context()for token exchange requests. This is safe for local automation. - Port 1455 in use: kill any process using that port, or change
REDIRECT_PORTin the script. - Stale OTP codes: if the inbox has old verification emails, the script may pick up an expired code. Clear the inbox or wait for a fresh email.
opencode-multi-auth add <alias>-> add account via OAuthopencode-multi-auth remove <alias>-> remove accountopencode-multi-auth list-> list configured accountsopencode-multi-auth status-> full statusopencode-multi-auth path-> print store pathopencode-multi-auth web --host 127.0.0.1 --port 3434-> run dashboardopencode-multi-auth service install|disable|status-> systemd user service helpers
GET /api/stateGET /api/logsPOST /api/syncPOST /api/auth/startPOST /api/switchPOST /api/removePOST /api/account/metaPOST /api/token/refreshPOST /api/limits/refreshPOST /api/limits/stopGET /api/accountsPUT /api/accounts/:alias/enabledPOST /api/accounts/:alias/reauthGET /api/forcePOST /api/forcePOST /api/force/clearGET /api/settingsPUT /api/settingsGET /api/settings/feature-flagsPUT /api/settings/feature-flagsPOST /api/settings/resetPOST /api/settings/presetPOST /api/antigravity/refresh(feature-flag gated)POST /api/antigravity/refresh-all(feature-flag gated)
OPENCODE_MULTI_AUTH_STORE_DIR-> override store directoryOPENCODE_MULTI_AUTH_STORE_FILE-> override store file pathOPENCODE_MULTI_AUTH_CODEX_AUTH_FILE-> override Codexauth.jsonCODEX_SOFT_STORE_PASSPHRASE-> encrypt account store at restCODEX_SOFT_LOG_PATH-> override dashboard log path
OPENCODE_MULTI_AUTH_ROTATION_STRATEGY(settings source override; runtime rotation follows persisted dashboard settings)OPENCODE_MULTI_AUTH_CRITICAL_THRESHOLDOPENCODE_MULTI_AUTH_LOW_THRESHOLDOPENCODE_MULTI_AUTH_TOKEN_FAILURE_COOLDOWN_MSOPENCODE_MULTI_AUTH_PROBE_EFFORTOPENCODE_MULTI_AUTH_LIMITS_PROBE_MODELS
OPENCODE_MULTI_AUTH_PREFER_CODEX_LATESTOPENCODE_MULTI_AUTH_CODEX_LATEST_MODELOPENCODE_MULTI_AUTH_INJECT_MODELSOPENCODE_MULTI_AUTH_TRUNCATIONOPENCODE_MULTI_AUTH_DEBUG
OPENCODE_MULTI_AUTH_ANTIGRAVITY_ENABLED
OPENCODE_MULTI_AUTH_NOTIFYOPENCODE_MULTI_AUTH_NOTIFY_SOUNDOPENCODE_MULTI_AUTH_NOTIFY_MAC_OPENOPENCODE_MULTI_AUTH_NOTIFY_NTFY_URLOPENCODE_MULTI_AUTH_NOTIFY_NTFY_TOKENOPENCODE_MULTI_AUTH_NOTIFY_UI_BASE_URL
- Dashboard host is loopback-only (
127.0.0.1,::1,localhost). - Non-loopback host bind is rejected.
- Sensitive token patterns are redacted in logs.
- Store file permissions are restricted (
0o600). - Antigravity APIs are blocked when feature flag is off.
npm ci
npm run lint
npm run build
npx tsc --noEmit
npm run test:unit
npm run test:integration
npm run test:web:headless
npm run test:failure
npm run test:stress
npm run test:sandbox
npm run test:soak:48hCurrent test script surfaces are scaffolded and active. For true long soak, set a long duration and keep the run alive.
Use codextesting.md for the Codex CLI live-testing checklist and copy-paste command flow.
- If dashboard start fails with localhost error, check
--hostand use loopback only. - If a request returns
INVALID_JSON, verify payload body is valid JSON. - If an alias action returns
ACCOUNT_NOT_FOUND, refresh account list first. - If re-auth is blocked with
ACCOUNT_DISABLED, enable the account before re-auth. - If encrypted store appears locked, export
CODEX_SOFT_STORE_PASSPHRASEbefore launching.
- Edit
src/*, never hand-editdist/*. - Run
npm run buildafter source changes. - Keep manual/live tests sandboxed (temp HOME/store/auth paths).
MIT