mirror of
https://github.com/openclaw/openclaw.git
synced 2026-02-19 18:39:20 -05:00
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
This commit is contained in:
82
extensions/openai-codex-auth/README.md
Normal file
82
extensions/openai-codex-auth/README.md
Normal file
@@ -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).
|
||||
160
extensions/openai-codex-auth/index.ts
Normal file
160
extensions/openai-codex-auth/index.ts
Normal file
@@ -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<ProviderAuthResult> => {
|
||||
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<string, object> = {};
|
||||
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;
|
||||
9
extensions/openai-codex-auth/openclaw.plugin.json
Normal file
9
extensions/openai-codex-auth/openclaw.plugin.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"id": "openai-codex-auth",
|
||||
"providers": ["openai-codex"],
|
||||
"configSchema": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {}
|
||||
}
|
||||
}
|
||||
15
extensions/openai-codex-auth/package.json
Normal file
15
extensions/openai-codex-auth/package.json
Normal file
@@ -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"
|
||||
]
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user