From 3ac422fe2e8b6c453e684f8f59bf445778ff7449 Mon Sep 17 00:00:00 2001 From: Ralph Date: Mon, 16 Feb 2026 12:27:53 +0100 Subject: [PATCH] feat(extensions): add OpenAI Codex CLI auth provider Adds a new authentication provider that reads OAuth tokens from the OpenAI Codex CLI (~/.codex/auth.json) to authenticate with OpenAI's API. This allows ChatGPT Plus/Pro subscribers to use OpenAI models in OpenClaw without needing a separate API key - just authenticate with 'codex login' first, then enable this plugin. Features: - Reads existing Codex CLI credentials from ~/.codex/auth.json - Supports all Codex-available models (gpt-4.1, gpt-4o, o1, o3, etc.) - Automatic token expiry detection from JWT - Clear setup instructions and troubleshooting docs Usage: openclaw plugins enable openai-codex-auth openclaw models auth login --provider openai-codex --set-default --- extensions/openai-codex-auth/README.md | 82 +++++++++ extensions/openai-codex-auth/index.ts | 160 ++++++++++++++++++ .../openai-codex-auth/openclaw.plugin.json | 9 + extensions/openai-codex-auth/package.json | 15 ++ 4 files changed, 266 insertions(+) create mode 100644 extensions/openai-codex-auth/README.md create mode 100644 extensions/openai-codex-auth/index.ts create mode 100644 extensions/openai-codex-auth/openclaw.plugin.json create mode 100644 extensions/openai-codex-auth/package.json diff --git a/extensions/openai-codex-auth/README.md b/extensions/openai-codex-auth/README.md new file mode 100644 index 0000000000..dd1e639b8a --- /dev/null +++ b/extensions/openai-codex-auth/README.md @@ -0,0 +1,82 @@ +# OpenAI Codex CLI Auth (OpenClaw plugin) + +Use OpenAI models with your **ChatGPT Plus/Pro subscription** via the Codex CLI OAuth tokens. + +This plugin reads authentication from the [OpenAI Codex CLI](https://github.com/openai/codex) and uses those OAuth credentials to access OpenAI models — no separate API key required. + +## Enable + +Bundled plugins are disabled by default. Enable this one: + +```bash +openclaw plugins enable openai-codex-auth +``` + +Restart the Gateway after enabling. + +## Prerequisites + +1. **ChatGPT Plus or Pro subscription** — required for Codex CLI access +2. **Codex CLI installed and authenticated**: + +```bash +# Install Codex CLI +npm install -g @openai/codex + +# Authenticate (opens browser for OAuth) +codex login +``` + +This creates `~/.codex/auth.json` with your OAuth tokens. + +## Authenticate with OpenClaw + +After Codex CLI is authenticated: + +```bash +openclaw models auth login --provider openai-codex --set-default +``` + +## Available Models + +The following models are available through Codex CLI authentication: + +- `openai/gpt-4.1`, `openai/gpt-4.1-mini`, `openai/gpt-4.1-nano` +- `openai/gpt-4o`, `openai/gpt-4o-mini` +- `openai/o1`, `openai/o1-mini`, `openai/o1-pro` +- `openai/o3`, `openai/o3-mini` +- `openai/o4-mini` + +Default model: `openai/o3` + +## How It Works + +1. The plugin reads `~/.codex/auth.json` created by `codex login` +2. OAuth tokens from your ChatGPT subscription are extracted +3. OpenClaw uses these tokens to authenticate with OpenAI's API +4. Tokens auto-refresh when needed (handled by OpenClaw's credential system) + +## Why Use This? + +- **No separate API key** — use your existing ChatGPT Plus/Pro subscription +- **No usage-based billing** — covered by your subscription +- **Access to latest models** — same models available in ChatGPT + +## Troubleshooting + +### "No Codex auth found" + +Run `codex login` to authenticate the Codex CLI first. + +### Tokens expired + +Re-run `codex login` to refresh your tokens, then re-authenticate: + +```bash +codex login +openclaw models auth login --provider openai-codex --set-default +``` + +### Model not available + +Some models may require specific subscription tiers (e.g., o1-pro requires ChatGPT Pro). diff --git a/extensions/openai-codex-auth/index.ts b/extensions/openai-codex-auth/index.ts new file mode 100644 index 0000000000..1c9ef1cafd --- /dev/null +++ b/extensions/openai-codex-auth/index.ts @@ -0,0 +1,160 @@ +import { + emptyPluginConfigSchema, + type OpenClawPluginApi, + type ProviderAuthContext, + type ProviderAuthResult, +} from "openclaw/plugin-sdk"; +import * as fs from "node:fs"; +import * as path from "node:path"; +import * as os from "node:os"; + +const PROVIDER_ID = "openai-codex"; +const PROVIDER_LABEL = "OpenAI Codex CLI"; +const AUTH_FILE = path.join(os.homedir(), ".codex", "auth.json"); + +/** + * OpenAI Codex models available via ChatGPT Plus/Pro subscription. + * These are the models exposed through the Codex CLI OAuth tokens. + */ +const CODEX_MODELS = [ + "openai/gpt-4.1", + "openai/gpt-4.1-mini", + "openai/gpt-4.1-nano", + "openai/gpt-4o", + "openai/gpt-4o-mini", + "openai/o1", + "openai/o1-mini", + "openai/o1-pro", + "openai/o3", + "openai/o3-mini", + "openai/o4-mini", +] as const; + +const DEFAULT_MODEL = "openai/o3"; + +interface CodexAuthTokens { + access_token: string; + refresh_token?: string; + account_id?: string; + expires_at?: number; +} + +interface CodexAuthFile { + tokens?: CodexAuthTokens; +} + +/** + * Read the Codex CLI auth.json file from ~/.codex/auth.json + */ +function readCodexAuth(): CodexAuthFile | null { + try { + if (!fs.existsSync(AUTH_FILE)) return null; + const content = fs.readFileSync(AUTH_FILE, "utf-8"); + return JSON.parse(content) as CodexAuthFile; + } catch { + return null; + } +} + +/** + * Decode JWT expiry timestamp from access token + */ +function decodeJwtExpiry(token: string): number | undefined { + try { + const payload = token.split(".")[1]; + if (!payload) return undefined; + const decoded = JSON.parse(Buffer.from(payload, "base64").toString()) as { exp?: number }; + return decoded.exp ? decoded.exp * 1000 : undefined; + } catch { + return undefined; + } +} + +const openaiCodexPlugin = { + id: "openai-codex-auth", + name: "OpenAI Codex Auth", + description: "Use OpenAI models via Codex CLI authentication (ChatGPT Plus/Pro)", + configSchema: emptyPluginConfigSchema(), + + register(api: OpenClawPluginApi) { + api.registerProvider({ + id: PROVIDER_ID, + label: PROVIDER_LABEL, + docsPath: "/providers/models", + aliases: ["codex", "chatgpt"], + + auth: [ + { + id: "codex-cli", + label: "Codex CLI Auth", + hint: "Use existing Codex CLI authentication from ~/.codex/auth.json", + kind: "custom", + + run: async (ctx: ProviderAuthContext): Promise => { + const spin = ctx.prompter.progress("Reading Codex CLI auth…"); + + try { + const auth = readCodexAuth(); + + if (!auth?.tokens?.access_token) { + spin.stop("No Codex auth found"); + await ctx.prompter.note( + "Run 'codex login' first to authenticate with OpenAI.\n\n" + + "Install Codex CLI: npm install -g @openai/codex\n" + + "Then run: codex login", + "Setup required", + ); + throw new Error("Codex CLI not authenticated. Run: codex login"); + } + + spin.stop("Codex auth loaded"); + + const profileId = `openai-codex:${auth.tokens.account_id ?? "default"}`; + const expires = auth.tokens.expires_at + ? auth.tokens.expires_at * 1000 + : decodeJwtExpiry(auth.tokens.access_token); + + const modelsConfig: Record = {}; + for (const model of CODEX_MODELS) { + modelsConfig[model] = {}; + } + + return { + profiles: [ + { + profileId, + credential: { + type: "oauth", + provider: PROVIDER_ID, + access: auth.tokens.access_token, + refresh: auth.tokens.refresh_token ?? "", + expires: expires ?? Date.now() + 3600000, + }, + }, + ], + configPatch: { + agents: { + defaults: { + models: modelsConfig, + }, + }, + }, + defaultModel: DEFAULT_MODEL, + notes: [ + "Using Codex CLI auth from ~/.codex/auth.json", + `Available models: ${CODEX_MODELS.join(", ")}`, + "Tokens auto-refresh when needed.", + ], + }; + } catch (err) { + spin.stop("Failed to load Codex auth"); + throw err; + } + }, + }, + ], + }); + }, +}; + +export default openaiCodexPlugin; diff --git a/extensions/openai-codex-auth/openclaw.plugin.json b/extensions/openai-codex-auth/openclaw.plugin.json new file mode 100644 index 0000000000..92d11baf7b --- /dev/null +++ b/extensions/openai-codex-auth/openclaw.plugin.json @@ -0,0 +1,9 @@ +{ + "id": "openai-codex-auth", + "providers": ["openai-codex"], + "configSchema": { + "type": "object", + "additionalProperties": false, + "properties": {} + } +} diff --git a/extensions/openai-codex-auth/package.json b/extensions/openai-codex-auth/package.json new file mode 100644 index 0000000000..4f37e94e49 --- /dev/null +++ b/extensions/openai-codex-auth/package.json @@ -0,0 +1,15 @@ +{ + "name": "@openclaw/openai-codex-auth", + "version": "2026.2.16", + "private": true, + "description": "OpenAI Codex CLI auth provider plugin - use ChatGPT Plus/Pro subscription for OpenAI models", + "type": "module", + "devDependencies": { + "openclaw": "workspace:*" + }, + "openclaw": { + "extensions": [ + "./index.ts" + ] + } +}