# How the Codex Plugin Handles ChatGPT Authentication vs API Key Authentication

> Discover how the Codex plugin handles ChatGPT authentication versus API keys. Learn about verified login sessions and unverified API keys via the buildAppServerAuthStatus function.

- Repository: [OpenAI/codex-plugin-cc](https://github.com/openai/codex-plugin-cc)
- Tags: internals
- Published: 2026-08-04

---

**The Codex plugin authenticates users by querying the Codex app-server for account information, distinguishing between ChatGPT login sessions (verified) and API keys (unverified) through the `buildAppServerAuthStatus` function in `plugins/codex/scripts/lib/codex.mjs`.**

This article examines how the openai/codex-plugin-cc repository implements dual authentication paths, letting users connect via their ChatGPT accounts or raw API credentials. Understanding these mechanisms is essential for developers integrating Codex into custom environments where authentication flexibility matters.

## How Authentication Discovery Works

The plugin initiates authentication discovery by making two remote procedure calls to the Codex app-server:

1. **`account/read`** – Retrieves the current account type and metadata
2. **`config/read`** – Fetches provider configuration including `requiresOpenaiAuth` flags

These calls happen within `getCodexAuthStatusFromClient`, which delegates the response parsing to `buildAppServerAuthStatus`. The function examines the account type field and branches into three distinct paths.

## ChatGPT Account Authentication (Verified)

When the server returns `type: "chatgpt"`, the plugin constructs a fully verified authentication object. This path starts at line 24 of `buildAppServerAuthStatus` in `plugins/codex/scripts/lib/codex.mjs`.

The resulting object structure:

```javascript
{
  loggedIn: true,
  detail: "ChatGPT login active for alice@example.com", // email included when available
  source: "app-server",
  authMethod: "chatgpt",
  verified: true,
  provider: <providerId>
}

```

**Key characteristics of ChatGPT authentication:**

- **Verified status** – The server has validated the session through OpenAI's OAuth flow
- **User identification** – Optional email address surfaces in the detail string for CLI feedback
- **Provider binding** – The `provider` field captures which backend serves the request

This path represents the most seamless user experience, as no manual API key management is required.

## API Key Authentication (Unverified)

When the account type equals `"apiKey"`, the plugin treats the credential as present but unverified. This branch begins at line 36 of the same function.

The resulting object structure:

```javascript
{
  loggedIn: true,
  detail: "API key configured (unverified)",
  source: "app-server",
  authMethod: "apiKey",
  verified: false,
  provider: <providerId>
}

```

**Critical distinction:** The `verified: false` flag exists because the Codex app-server lacks the OpenAI token needed to validate the key's authenticity. The plugin trusts that the key exists in configuration but cannot confirm it works until an actual API call is attempted.

This design reflects a security boundary—the plugin delegates credential storage to the app-server while remaining agnostic about key validity.

## Provider-Agnostic Authentication Bypass

The `config/read` response includes a `requiresOpenaiAuth` boolean. When this value is `false`, the plugin short-circuits to a successful login status regardless of account type. This enables deployment scenarios with:

- Self-hosted Codex instances without OpenAI dependencies
- Enterprise environments using alternative model providers
- Offline or air-gapped development workflows

If `requiresOpenaiAuth` is true and neither ChatGPT nor API key credentials are present, the function returns a "not authenticated" fallback.

## Practical Implementation Example

Query and display the current authentication state using the internal client utilities:

```javascript
// Example: query the auth status from a running Codex client
import { getCodexAuthStatusFromClient } from "./plugins/codex/scripts/lib/codex.mjs";

async function showAuthStatus() {
  const client = createCodexClient(); // whatever creates the Codex RPC client
  const cwd = process.cwd();
  const status = await getCodexAuthStatusFromClient(client, cwd);
  console.log(status);
}

/* Sample output when the user is logged in with a ChatGPT account
{
  loggedIn: true,
  detail: "ChatGPT login active for alice@example.com",
  source: "app-server",
  authMethod: "chatgpt",
  verified: true,
  provider: "openai"
}
*/

/* Sample output when an API key is present but not verified
{
  loggedIn: true,
  detail: "API key configured (unverified)",
  source: "app-server",
  authMethod: "apiKey",
  verified: false,
  provider: "openai"
}
*/

```

The `status` command in the CLI consumes this same object to render human-readable authentication feedback.

## Key Files and Their Roles

Understanding the complete authentication flow requires familiarity with these source files:

| File | Purpose |
|------|---------|
| `plugins/codex/scripts/lib/codex.mjs` | Core logic implementing `buildAppServerAuthStatus` and `getCodexAuthStatusFromClient` |
| `tests/runtime.test.mjs` | Test coverage verifying that API-key auth succeeds where plain login would fail |
| `plugins/codex/scripts/lib/client.mjs` | RPC client factory for `account/read` and `config/read` invocations |
| [`README.md`](https://github.com/openai/codex-plugin-cc/blob/main/README.md) | High-level configuration guidance for authentication setup |

## Security and UX Trade-offs

The authentication design encodes intentional trade-offs:

- **ChatGPT login** prioritizes convenience and verified trust at the cost of OAuth dependency
- **API keys** enable automation and headless environments but defer validation to runtime
- **Unverified flag** prevents false confidence while allowing configuration to proceed

According to the openai/codex-plugin-cc source code, these paths coexist to support both interactive development workflows and CI/CD pipelines without forcing a single authentication model.

## Summary

- The Codex plugin queries the app-server via `account/read` and `config/read` to determine authentication state
- **`buildAppServerAuthStatus`** in `plugins/codex/scripts/lib/codex.mjs` implements the branching logic at lines 24-45
- **ChatGPT accounts** receive `verified: true` status with optional email identification
- **API keys** are acknowledged as `loggedIn: true` but marked `verified: false` due to server-side validation limitations
- The `requiresOpenaiAuth` configuration flag enables provider-agnostic authentication bypass

## Frequently Asked Questions

### Can the plugin verify API keys without making an actual OpenAI request?

No. As implemented in `buildAppServerAuthStatus`, API key authentication intentionally returns `verified: false` because the Codex app-server does not possess an OpenAI token to validate the key. Verification only occurs when the key is used in a subsequent API call. This design choice prevents unnecessary token consumption during status checks while surfacing the uncertainty to users.

### What happens if both ChatGPT and API key credentials are configured?

The plugin prioritizes the account type returned by the app-server's `account/read` response. There is no merge logic—the `type` field exclusively determines whether the ChatGPT branch (line 24) or API key branch (line 36) executes. Server-side configuration dictates which authentication method takes precedence.

### How does the plugin handle authentication when `requiresOpenaiAuth` is false?

The function shortcuts to a successful authentication status without examining account details. This path supports non-OpenAI providers and self-hosted deployments by treating the authentication requirement as satisfied regardless of credential presence. The implementation respects the provider's declared capabilities over OpenAI-specific validation.

### Where can I find test coverage for the API key authentication path?

The `tests/runtime.test.mjs` file contains assertions specifically validating that API-key authentication succeeds in scenarios where standard login would fail. These tests ensure the plugin correctly trusts server-reported API key status even when OAuth flows are unavailable or misconfigured.