# 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)