magi-code 0.63.4

Repository-aware CLI coding agent for terminal work
Documentation
# Provider authentication

[Feature docs index](README.md) · [Repository README](../../README.md)

## Purpose

Authenticate `openai-codex` with provider-keyed OAuth, use first-class Anthropic Messages API-key auth, use direct Claude Code OAuth/API-key auth through `claude-code`, or configure OpenAI-compatible custom providers without mixing credential types.

## Details

Never commit real credentials, copied tokens, account ids, terminal auth output, or transcripts containing secrets.

### Anthropic API-key provider: `anthropic`

`anthropic` is a first-class Anthropic Messages API provider. It uses Anthropic API billing credits, not Claude Code subscription, Claude Code OAuth, `claude auth login`, or Claude credential files.

Runtime auth uses `ANTHROPIC_API_KEY` first, then provider-keyed API-key auth in `~/.magi-code/auth.json`. `OPENAI_API_KEY`, `MC_API_KEY`, and `--api-key` are ignored for Anthropic to avoid sending wrong-provider secrets.

```sh
export ANTHROPIC_API_KEY="<ANTHROPIC_API_KEY>"
magi-code --provider anthropic --model claude-sonnet-4-5-20250929 --print "Reply with only: ok"
```

Non-secret selected model example:

```json
{
  "selected_model": {
    "provider": "anthropic",
    "model": "claude-sonnet-4-5-20250929"
  }
}
```

Use `/setmodel anthropic/<model-name>` after model catalog discovery. Missing Anthropic auth does not block Codex or custom provider catalogs.

### Claude Code direct provider: `claude-code`

`claude-code` is a direct blocking Anthropic Messages API provider that uses Claude Code OAuth credentials first. It does not spawn `claude -p` for provider execution.

```sh
claude auth login
magi-code --provider claude-code --model sonnet --print "Reply with only: ok"
```

Credential priority:

1. macOS Keychain service `Claude Code-credentials`.
2. `~/.claude/.credentials.json` with Claude Code `claudeAiOauth` access/refresh tokens.
3. Explicit provider-keyed API-key fallback in `~/.magi-code/auth.json` or `$MC_HOME/auth.json`:

```json
{
  "claude-code": { "type": "api_key", "key": "<ANTHROPIC_API_KEY>" }
}
```

OAuth refresh is transparent before requests. File-source refresh writes back to `~/.claude/.credentials.json` with owner-only permissions; Keychain-source refresh is read-only for this version. If Keychain refresh-token rotation breaks later runs, run `claude auth login` again.

API-key fallback bills Anthropic API credits. It is not Claude Code subscription access. `--api-key`, `MC_API_KEY`, `OPENAI_API_KEY`, and ambient `ANTHROPIC_API_KEY` do not satisfy `claude-code`; only the explicit provider-keyed `claude-code` auth record is used for API-key fallback.

#### OAuth billing route marker

Claude Code OAuth requests POST to `https://api.anthropic.com/v1/messages?beta=true`. OAuth request bodies prepend this marker to `system` text:

```text
x-anthropic-billing-header: cc_version=2.1.185; cc_entrypoint=sdk-cli; cch=00000;
```

This is a body-level system text block, not an HTTP header. `src/providers/claude_code/body.rs` injects it only when `ClaudeCodeAccessMode::is_oauth()` is true. API-key fallback excludes it and bills Anthropic API credits.

Without the marker, premium Claude Code models can route to default Claude.ai OAuth quota and return `429 rate_limit_error` despite valid Claude Code credentials. Claude Code `view_image` OAuth requests use the same marker path in `src/tools/view_image.rs`.

Current static `/setmodel` model aliases:

| Alias | Anthropic model id |
| --- | --- |
| `claude-code/sonnet` / `sonnet` | `claude-sonnet-4-6` |
| `claude-code/opus` / `opus` | `claude-opus-4-8` |
| `claude-code/fable` / `fable` | `claude-fable-5` |

`src/model_catalog.rs` owns alias resolution in `resolve_claude_code_model_alias()`.

### Custom OpenAI-compatible providers

Use `/login custom-provider` to add a provider. Setup stores only non-secret metadata in `~/.magi-code/settings.json`: provider id, display label, normalized API-root base URL, optional API-key environment variable name, optional `models_dev_provider` namespace for catalog metadata enrichment, optional provider-local `use_responses_endpoint` endpoint mode, optional `supports_text_verbosity` capability, and optional `extra_models` catalog override ids.

Custom providers use `{base_url}/chat/completions` by default. Set non-secret `custom_providers.<id>.use_responses_endpoint` to `true` in `settings.json` to use `{base_url}/responses` instead; model discovery still uses `{base_url}/models`. Set `supports_text_verbosity` to `true` only when provider accepts OpenAI Responses `text.verbosity`; capability defaults false. Shared `openai_responses.text_verbosity` must also be set for field emission. `/login custom-provider` does not prompt for these in v1, and there is no automatic endpoint detection. `openai-codex` remains separate and unaffected.

`openai_responses.text_verbosity` accepts `low`, `medium`, or `high`. Shared setting overrides legacy Codex setting; custom providers never inherit legacy Codex value. Omitted shared setting preserves custom request shape. Verbosity controls visible answer detail and may affect output size, latency, and cost; it does not control reasoning effort, hidden chain-of-thought, tool calls, or hard output-token limits.

Provider ids use lowercase slug syntax such as `local-provider`; `openai-codex` is reserved. You may use a custom provider id such as `openai` if you want to configure OpenAI through the custom-provider workflow. If an API-key env var is configured, only that named variable is read at runtime and it must be non-empty for the provider to be ready.

If provider `/models` omits a working model, add provider-local non-secret `extra_models`. Example for Z.ai Coding Plan:

```json
{
  "custom_providers": {
    "zai": {
      "label": "Z.ai",
      "base_url": "https://api.z.ai/api/coding/paas/v4",
      "api_key_env_var": "ZAI_API_KEY",
      "extra_models": ["glm-5.2"]
    }
  }
}
```

`extra_models` augments discovered `/models` results and dedupes if upstream later lists same model. It does not store API keys, does not accept `zai/glm-5.2` qualified ids, and does not change chat-completions vs responses endpoint behavior.

`models_dev_provider` is not auth. It is optional non-secret exact `models.dev` provider namespace metadata, for example `openrouter`, used only to enrich matching custom model ids with context/reasoning/output-token metadata. Explicit values override provider-id fallback. When omitted, magi-code uses the custom provider id (`custom_providers.<id>`) as the exact `models.dev` namespace; a custom provider id `openai` therefore uses namespace `openai`. Enrichment still requires exact namespace and model id matches, with no label, host, model-prefix, or base-URL inference. If your provider id differs from the desired `models.dev` namespace, set `models_dev_provider` explicitly; for example, provider id `custom-openai` using the OpenAI API root needs `models_dev_provider: "openai"` to use OpenAI metadata.

```sh
# No-auth local provider:
magi-code --provider local-provider --model model-name --print "Reply with only: ok"

# Env-var-backed provider:
export HOSTED_PROVIDER_API_KEY="<CUSTOM_PROVIDER_API_KEY>"
magi-code --provider hosted-provider --model model-name --print "Reply with only: ok"
```

Use `/logout <custom-provider-id>` to remove local custom provider metadata. This does not touch credentials, sessions, unrelated settings, or other providers.

### Codex backend provider: `openai-codex`

`openai-codex` uses the Codex backend responses endpoint at `https://chatgpt.com/backend-api/codex/responses` and requires provider-keyed OAuth credentials plus a ChatGPT account id.

Recommended setup:

```text
/login openai-codex
```

The login flow starts a ChatGPT account browser OAuth flow, displays the authorization URL in the active interface, binds a loopback listener to `127.0.0.1:1455` for the registered redirect URI `http://localhost:1455/auth/callback`, and stores credentials in `~/.magi-code/auth.json` or `$MC_HOME/auth.json`. Mission Control supports `Ctrl-Y` to copy the URL and `Ctrl-O` to open it in a browser. If loopback callback fails, both classic shell and Mission Control provide a transient manual paste fallback for the final redirect URL or authorization code.

Do not pass Codex OAuth tokens through `--api-key`, `MC_API_KEY`, or `OPENAI_API_KEY`. The runtime refuses API-key/runtime-token auth for `openai-codex` to avoid sending the wrong secret to the wrong transport.

Logout is local-only:

```text
/logout openai-codex
```

It removes the local OpenAI Codex OAuth record from `auth.json`; it does not revoke remote provider tokens or sign out browser sessions.

Live smoke after authentication:

```sh
magi-code --provider openai-codex --model gpt-5.5 --print "Reply with only: ok"
```

---

[Back to feature docs](README.md) · [Back to repository README](../../README.md)