From 031beb1751031fed377fcd5760c4d257b259b1e3 Mon Sep 17 00:00:00 2001 From: Wolfgang Schoenberger <221313372+wolfiesch@users.noreply.github.com> Date: Wed, 29 Jul 2026 06:56:38 -0700 Subject: [PATCH] docs(auth): correct credential precedence (cherry picked from commit 33ede5efbc52cedc9819cb65c642cfeab82c337c) --- docs/auth-broker-gateway.md | 2 +- docs/environment-variables.md | 2 +- docs/models.md | 12 +++++++----- docs/providers.md | 15 ++++++++------- 4 files changed, 17 insertions(+), 14 deletions(-) diff --git a/docs/auth-broker-gateway.md b/docs/auth-broker-gateway.md index d1cfd21ff..9ca2e513a 100644 --- a/docs/auth-broker-gateway.md +++ b/docs/auth-broker-gateway.md @@ -219,5 +219,5 @@ The broker only owns OAuth credentials and provider-API-key credentials that wer ## See also - [`secrets.md`](./secrets.md) — secret obfuscation around tokens that _do_ leak through (e.g. `OMP_AUTH_BROKER_TOKEN` in shell output). -- [`models.md`](./models.md) — provider auth resolution order; the broker plugs in at layers 2–3 (stored credentials). +- [`models.md`](./models.md) — provider auth resolution order; the broker supplies the stored-credential layers. - [`environment-variables.md`](./environment-variables.md) — full env reference including `OMP_AUTH_BROKER_URL` / `OMP_AUTH_BROKER_TOKEN`. diff --git a/docs/environment-variables.md b/docs/environment-variables.md index b23122623..bf69a11f3 100644 --- a/docs/environment-variables.md +++ b/docs/environment-variables.md @@ -267,7 +267,7 @@ SearXNG also reads the equivalent `searxng.endpoint`, `searxng.token`, `searxng. `searchAnthropic()` resolves credentials in this order: 1. `ANTHROPIC_SEARCH_API_KEY` -2. `authStorage.getApiKey("anthropic")` fallback credentials (runtime/config overrides, stored API-key credentials, stored OAuth credentials, then generic Anthropic env fallback: `ANTHROPIC_FOUNDRY_API_KEY` in Foundry mode, otherwise `ANTHROPIC_OAUTH_TOKEN` / `ANTHROPIC_API_KEY`) +2. `authStorage.getApiKey("anthropic")` fallback credentials (runtime and config overrides, stored OAuth, a login-sourced API key, generic Anthropic environment fallback, then other stored API keys; the generic environment fallback is `ANTHROPIC_FOUNDRY_API_KEY` in Foundry mode, otherwise `ANTHROPIC_OAUTH_TOKEN` or `ANTHROPIC_API_KEY`) For either credential path, base URL resolution is: diff --git a/docs/models.md b/docs/models.md index e77cfb840..38d9f6cf9 100644 --- a/docs/models.md +++ b/docs/models.md @@ -379,10 +379,12 @@ Extensions can register providers at runtime (`pi.registerProvider(...)`), inclu When requesting a key for a provider, effective order is: 1. Runtime override (CLI `--api-key`) -2. Stored API key credential in `agent.db` -3. Stored OAuth credential in `agent.db` (with refresh) -4. Environment variable mapping (`OPENAI_API_KEY`, `ANTHROPIC_API_KEY`, etc.) -5. ModelRegistry fallback resolver (provider `apiKey` from `models.yml`, env-name-or-literal semantics) +2. Config override (`models.yml` `providers..apiKey`) +3. Stored OAuth credential (with refresh) +4. Login-sourced stored API key +5. Environment variable mapping (`OPENAI_API_KEY`, `ANTHROPIC_API_KEY`, etc.) +6. Other stored API key, such as a broker-migrated copy +7. ModelRegistry fallback resolver (`models.yml` custom providers, using env-name-or-literal semantics) `models.yml` `apiKey` behavior: @@ -400,7 +402,7 @@ Keyless providers: ### Broker mode -When `OMP_AUTH_BROKER_URL` (or `auth.broker.url`) is set, the local SQLite credential store is replaced by `RemoteAuthCredentialStore`. Layers 2 and 3 above (stored API key / OAuth in `agent.db`) are served from a broker-supplied snapshot whose `refresh` tokens are redacted; expiry triggers `POST /v1/credential/:id/refresh` on the broker rather than a local refresh. +When `OMP_AUTH_BROKER_URL` (or `auth.broker.url`) is set, the local SQLite credential store is replaced by `RemoteAuthCredentialStore`. Layers 3, 4, and 6 above (stored OAuth and API-key credentials) are served from a broker-supplied snapshot whose `refresh` tokens are redacted; expiry triggers `POST /v1/credential/:id/refresh` on the broker rather than a local refresh. `AuthStorage.setConfigApiKey` lets a `models.yml` `apiKey` win over a broker-resolved OAuth token without overriding a runtime `--api-key`. See [`auth-broker-gateway.md`](./auth-broker-gateway.md) for the full broker / gateway design and env surface (`OMP_AUTH_BROKER_URL`, `OMP_AUTH_BROKER_TOKEN`, `auth.broker.url`, `auth.broker.token`). diff --git a/docs/providers.md b/docs/providers.md index 487ef0c0c..c840fb50a 100644 --- a/docs/providers.md +++ b/docs/providers.md @@ -28,12 +28,13 @@ Keyless local engines are a special case: `ollama`, `llama.cpp`, and `lm-studio` When a provider needs an API key, `omp` resolves it in this order (first match wins): -1. **Runtime override** — a key supplied for the current process, e.g. CLI `--api-key`. Never persisted. -2. **`models.yml` config key** — an `apiKey` pinned on a custom provider, registered as a config-sourced bearer. This deliberately beats stored OAuth, so a key supplied for a custom `baseUrl`/gateway is honored instead of forwarding an upstream OAuth token the proxy would reject. -3. **Stored API key** — an API-key credential saved in the auth store. -4. **Stored OAuth credential** — refreshed when needed; multiple accounts are ranked/rotated automatically. For Anthropic and ChatGPT (Codex), each organization/workspace counts as its own account: one email holding both a Team/Enterprise seat and a personal plan can log in once per subscription (pick the workspace on the browser consent page) and rotation treats them as two accounts. -5. **Provider environment variable** — including values loaded from `.env` files (see [the env-var table](#environment-variables-and-env-files)). -6. **`models.yml` fallback resolver** — keys for custom providers not otherwise registered. +1. **Runtime override**: a key supplied for the current process, for example CLI `--api-key`. Never persisted. +2. **`models.yml` config key**: an `apiKey` pinned on a custom provider, registered as a config-sourced bearer. This deliberately beats stored OAuth, so a key supplied for a custom `baseUrl` or gateway is honored instead of forwarding an upstream OAuth token the proxy would reject. +3. **Stored OAuth credential**: refreshed when needed; multiple accounts are ranked and rotated automatically. For Anthropic and ChatGPT (Codex), each organization or workspace counts as its own account: one email holding both a Team or Enterprise seat and a personal plan can log in once per subscription (pick the workspace on the browser consent page), and rotation treats them as two accounts. +4. **Login-sourced stored API key**: an API-key credential saved by a successful `/login`. +5. **Provider environment variable**: including values loaded from `.env` files (see [the env-var table](#environment-variables-and-env-files)). +6. **Other stored API key**: for example, a broker-migrated key. This is a last resort so an explicit environment variable wins. +7. **`models.yml` fallback resolver**: keys for custom providers not otherwise registered. Stored credentials live in the auth store at `~/.omp/agent/agent.db` for local auth, or in the configured auth-broker snapshot when running in broker mode. (`PI_CODING_AGENT_DIR` relocates the `~/.omp/agent` base, and the auth store moves with it.) @@ -344,7 +345,7 @@ disabledProviders: **A provider's models are not selectable.** Confirm the provider has credentials (`/login `, an exported environment variable, or a `models.yml` `apiKey`) and that its ID is not in the effective `disabledProviders` list. Remember the rule: not disabled **and** (keyless **or** has credentials). Keyless local engines only appear once the engine is actually running and responding. -**The wrong key is being used (a stale key from `.env`).** Resolution favors runtime `--api-key`, then a `models.yml` config key, then stored credentials, then environment/`.env`. An already-set process environment variable also beats every `.env` file, and `/.env` beats `~/.env`. If an unexpected key wins, check for an exported shell variable and the four `.env` files in precedence order, and clear the one that should not apply. +**The wrong key is being used (a stale key from `.env`).** Resolution favors runtime `--api-key`, then a `models.yml` config key, stored OAuth, a key saved by `/login`, environment or `.env`, other stored API keys, and finally the `models.yml` fallback resolver. An already-set process environment variable also beats every `.env` file, and `/.env` beats `~/.env`. If an unexpected key wins, check for an exported shell variable and the four `.env` files in precedence order, and clear the one that should not apply. **A provider still appears even though I disabled it.** `disabledProviders` arrays are replaced, not merged: a project `/.omp/config.yml` array fully overrides the global one. Verify the *effective* list for the directory you are in (path-scoped entries only apply at or under their configured path), and confirm the ID is spelled exactly. Use `omp config get disabledProviders` to inspect the merged value (see [Settings](./settings.md)).