Skip to content

feat: add OpenAI Codex OAuth PKCE install flow#1129

Open
eureka928 wants to merge 21 commits intoeigent-ai:mainfrom
eureka928:feat/codex-oauth
Open

feat: add OpenAI Codex OAuth PKCE install flow#1129
eureka928 wants to merge 21 commits intoeigent-ai:mainfrom
eureka928:feat/codex-oauth

Conversation

@eureka928
Copy link
Contributor

@eureka928 eureka928 commented Feb 2, 2026

Description

This PR adds support for installing and authenticating OpenAI Codex as a tool via OAuth PKCE flow. Users can install Codex from both the Settings/MCP page and the AddWorker tool selection, with automatic token management including refresh and expiry handling.

Closes #834

Key Changes:

Backend (backend/):

  • app/utils/toolkit/codex_toolkit.py — New CodexOAuthManager implementing the full OpenAI OAuth PKCE flow (authorization URL generation, token exchange, refresh, revocation, and persistent token storage via keyring)
  • app/controller/tool_controller.py — New endpoints for Codex install, uninstall, save-token, and status; integrated into existing /install/{tool} and /uninstall/{tool} routes

Server (server/):

  • app/model/config/config.py — Added CODEX config group with OPENAI_API_KEY environment variable mapping
  • app/type/config_group.py — Registered codex in ConfigGroup enum and CONFIG_GROUP_ENV_VARS

Frontend (src/):

  • src/pages/Setting/MCP.tsx — Codex card in Settings with install/uninstall buttons and OAuth callback handling
  • src/components/AddWorker/ToolSelect.tsx — Codex option in worker tool selection with installed state detection
  • src/hooks/useIntegrationManagement.ts — Codex integration status hook
  • src/components/IntegrationList/index.tsx — Codex entry in integration list

Files Changed:

  • backend/app/controller/tool_controller.py
  • backend/app/utils/toolkit/codex_toolkit.py (new)
  • server/app/model/config/config.py
  • server/app/type/config_group.py
  • src/components/AddWorker/ToolSelect.tsx
  • src/components/IntegrationList/index.tsx
  • src/hooks/useIntegrationManagement.ts
  • src/pages/Setting/MCP.tsx

What is the purpose of this pull request?

  • Bug fix
  • New Feature
  • Documentation update
  • Other

@eureka928
Copy link
Contributor Author

@Wendong-Fan @Pakchoioioi would you review my PR?
Thank you

@eureka928
Copy link
Contributor Author

Also, @Wendong-Fan would you check my DM on discord?
Thank you

@eureka928
Copy link
Contributor Author

Why these are cancelled?

@4pmtong
Copy link
Collaborator

4pmtong commented Feb 3, 2026

Hi @eureka928! Thanks for your contribution! I'm doing a detailed review, @Pakchoioioi Could you help review the OAuth flow?

@eureka928
Copy link
Contributor Author

Fixed the testing

@eureka928 eureka928 force-pushed the feat/codex-oauth branch 2 times, most recently from f33d37b to bdbc3e3 Compare February 4, 2026 09:11
@eureka928
Copy link
Contributor Author

Follow up on this

@Wendong-Fan Wendong-Fan requested a review from bytecii February 4, 2026 22:22
Copy link
Collaborator

@bytecii bytecii left a comment

Choose a reason for hiding this comment

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

Thanks. Left some comments

eureka928 added a commit to eureka928/eigent that referenced this pull request Feb 5, 2026
- Extract Codex config constants (CODEX_CONFIG_GROUP, CODEX_CONFIG_NAME,
  CODEX_POLL_TIMEOUT_MS) in ToolSelect.tsx
- Extract CODEX_TOKEN_PATH constant and clarify CODEX_CLIENT_ID is a
  fixed public value in codex_toolkit.py
- Simplify expires_in/expires_at: compute absolute expiry from relative
  value and only persist expires_at
- Add FileLock around token file reads/writes to prevent parallel
  update races
- Add TODO for response status string improvement and refactor of
  shared OAuth install logic
- Apply formatting suggestion on codex uninstall message
@eureka928
Copy link
Contributor Author

Hi @bytecii addressed all comments

@eureka928 eureka928 requested a review from 4pmtong February 5, 2026 04:54
@eureka928
Copy link
Contributor Author

I updated all, please review again

@eureka928 eureka928 requested review from 4pmtong and bytecii February 5, 2026 10:38
eureka928 added a commit to eureka928/eigent that referenced this pull request Feb 5, 2026
- Extract Codex config constants (CODEX_CONFIG_GROUP, CODEX_CONFIG_NAME,
  CODEX_POLL_TIMEOUT_MS) in ToolSelect.tsx
- Extract CODEX_TOKEN_PATH constant and clarify CODEX_CLIENT_ID is a
  fixed public value in codex_toolkit.py
- Simplify expires_in/expires_at: compute absolute expiry from relative
  value and only persist expires_at
- Add FileLock around token file reads/writes to prevent parallel
  update races
- Add TODO for response status string improvement and refactor of
  shared OAuth install logic
- Apply formatting suggestion on codex uninstall message
eureka928 added a commit to eureka928/eigent that referenced this pull request Feb 5, 2026
- Extract Codex config constants (CODEX_CONFIG_GROUP, CODEX_CONFIG_NAME,
  CODEX_POLL_TIMEOUT_MS) in ToolSelect.tsx
- Extract CODEX_TOKEN_PATH constant and clarify CODEX_CLIENT_ID is a
  fixed public value in codex_toolkit.py
- Simplify expires_in/expires_at: compute absolute expiry from relative
  value and only persist expires_at
- Add FileLock around token file reads/writes to prevent parallel
  update races
- Add TODO for response status string improvement and refactor of
  shared OAuth install logic
- Apply formatting suggestion on codex uninstall message
Copy link
Collaborator

@4pmtong 4pmtong left a comment

Choose a reason for hiding this comment

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

LGTM, thanks @eureka928 for contribution!

@Wendong-Fan Wendong-Fan added this to the Sprint 13 milestone Feb 6, 2026
@eureka928
Copy link
Contributor Author

@bytecii @Wendong-Fan please review again

const hasApiKey = configs.some(
(c: any) =>
c.config_group?.toLowerCase() === 'codex' &&
c.config_name === 'OPENAI_API_KEY' &&
Copy link
Contributor

@Wendong-Fan Wendong-Fan Feb 6, 2026

Choose a reason for hiding this comment

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

This check won't work - looking at config.py, Codex has env_vars: [] and stores the API key via Provider API, not as a config. So OPENAI_API_KEY will never exist in the codex config group.

We need to either save a marker config after OAuth (like Google Calendar does with GOOGLE_REFRESH_TOKEN), or check providers instead.

const response = await fetchPost('/install/tool/codex');
if (response.success) {
toast.success(t('setting.codex-installed-successfully'));
await saveCodexAsProvider(response);
Copy link
Contributor

Choose a reason for hiding this comment

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

Missing marker config save here. Google Calendar saves GOOGLE_REFRESH_TOKEN after OAuth to track install state, but Codex doesn't save anything. This means the UI will never show Codex as installed.

"""
path = cls._token_path()
try:
if "saved_at" not in token_data:
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: mutating the input dict directly (.pop(), key assignments) could cause issues if the caller reuses it. Consider working on a copy: data = token_data.copy()

# OpenAI API key). After OAuth the key is stored via the
# Provider API, not here. The entry is kept only for
# install-state detection in the integration list UI.
ConfigGroup.CODEX.value: {
Copy link
Contributor

@Wendong-Fan Wendong-Fan Feb 6, 2026

Choose a reason for hiding this comment

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

following up on my earlier comment, this entry acknowledges Codex is a provider (toolkit: None, type: provider), yet it still lives in ConfigInfo.configs alongside actual toolkits and appears in the MCP & Tools UI.

Suggestion: move the Codex OAuth entry point to Model/Provider settings page, since its purpose is obtaining an OpenAI API key for model access, not providing agent tools.

Copy link
Contributor

@Wendong-Fan Wendong-Fan left a comment

Choose a reason for hiding this comment

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

hey @eureka928 ,

Codex is explicitly marked as a provider, yet this PR still places it in MCP & Tools UI (MCP.tsx, ToolSelect.tsx, IntegrationList).

I saw the TODO comment in the code:

  # TODO: Codex is a model-provider integration, not a toolkit.
  # Its OAuth entry point should move to the Model/Provider settings page.

but since Codex OAuth should belongs in the Models/Provider settings page, not in MCP & Tools where users expect callable agent tools.

This should be fixed before merging rather than left as technical debt

eureka928 and others added 20 commits February 8, 2026 03:21
Implements Authorization Code + PKCE flow using Codex CLI's public
client_id. Handles background OAuth via localhost callback server,
token persistence at ~/.eigent/tokens/codex/, and refresh logic.
Add codex handling to install_tool and uninstall_tool endpoints.
Add POST /codex/save-token for manual API key fallback and
GET /codex/status for token status. Add Codex to available tools list.
Add CODEX enum to ConfigGroup and corresponding entry in
ConfigInfo.configs with OPENAI_API_KEY env var and codex_oauth toolkit.
Add Codex config check in useIntegrationManagement for installed state
and uninstall cleanup. Add Codex case in IntegrationList handleInstall
to trigger onInstall directly without env dialog.
Add Codex onInstall handler with OAuth status polling in MCP.tsx
settings page and ToolSelect.tsx AddWorker flow, following the
existing Google Calendar authorization pattern.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: bytecii <994513625@qq.com>
- Extract Codex config constants (CODEX_CONFIG_GROUP, CODEX_CONFIG_NAME,
  CODEX_POLL_TIMEOUT_MS) in ToolSelect.tsx
- Extract CODEX_TOKEN_PATH constant and clarify CODEX_CLIENT_ID is a
  fixed public value in codex_toolkit.py
- Simplify expires_in/expires_at: compute absolute expiry from relative
  value and only persist expires_at
- Add FileLock around token file reads/writes to prevent parallel
  update races
- Add TODO for response status string improvement and refactor of
  shared OAuth install logic
- Apply formatting suggestion on codex uninstall message
- Add Fernet encryption for token storage using cryptography library
- Derive encryption key from machine-specific identifiers (username,
  hostname, machine-id) using PBKDF2HMAC with 100k iterations
- Set restrictive file permissions (0600) on encrypted token file
- Tokens tied to specific machine for additional security
…t config

Address review feedback: Codex OAuth obtains an OpenAI API key for model
access, not agent tools. After successful OAuth, the key is now saved via
the Provider API (/api/provider) so it integrates with the model provider
configuration system.

Changes:
- Backend: return access_token in Codex install response for provider storage
- Frontend: replace /api/configs storage with /api/provider for Codex
- Server: mark CODEX ConfigInfo entry as type=provider with empty env_vars
- i18n: add missing codex translation keys, remove verbose t() fallback pattern
- Fix stray merge conflict marker in ToolSelect.tsx
- Remove debug console.log statements from MCP.tsx
- Save CODEX_OAUTH_TOKEN marker config after OAuth to track install state
- Check marker config instead of OPENAI_API_KEY for install detection
- Avoid mutating input dict in CodexOAuthManager.save_token()
- Add CODEX_OAUTH_TOKEN to Codex env_vars whitelist in server config
- Prioritize named integration descriptions over env_vars fallback
Codex OAuth is a model-provider integration, not a toolkit. Remove it
from ConfigInfo.configs so it no longer appears in the /api/config/info
response that drives the MCP & Tools UI. Also remove Codex-specific
install detection and uninstall handling from useIntegrationManagement
and IntegrationList.
Remove the entire Codex onInstall handler, saveCodexAsProvider, and
saveCodexMarkerConfig helpers from MCP.tsx and ToolSelect.tsx. Extract
OAuth polling constants (OAUTH_POLL_INTERVAL_MS, OAUTH_POLL_TIMEOUT_MS)
to replace inline magic numbers in the remaining Google Calendar flow.
Add TODO for status string enum extraction.
Add a "Connect via Codex" button to the OpenAI BYOK provider panel in
the Models settings page. The OAuth PKCE flow obtains an OpenAI API key
and saves it as a provider, with a marker config for state detection.

- Add handleCodexOAuth, saveCodexAsProvider, handleCodexDisconnect
- Extract refreshProviderForm helper to deduplicate provider list sync
- Show "or" divider between Codex OAuth and manual API key entry
- Disconnect properly revokes token, removes marker, and resets provider
- Add i18n keys for connect/disconnect/status UI text
@eureka928 eureka928 requested a review from Wendong-Fan February 8, 2026 02:29
@eureka928
Copy link
Contributor Author

@Wendong-Fan please review again, I addressed all comments

Copy link
Contributor

@Wendong-Fan Wendong-Fan left a comment

Choose a reason for hiding this comment

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

seems it's still organized as one toolkit?

Image

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.

[Feature Request] Add codex OAuth

4 participants