omp keeps every provider credential — OAuth refresh tokens, OAuth access tokens, stored API keys — in a single local SQLite file. /login writes to it, /logout clears entries from it, and provider calls read from it. When you need the same logins on more than one host, swap the local file for a remote broker without touching any other config.

The credential store

Credentials live in ~/.omp/agent/agent.db (or the equivalent under PI_CONFIG_DIR). One row per credential, multiple credentials per provider allowed — round-robin selection picks between them at call time.

The store holds three things per row: the provider id (anthropic, openai-codex, google-gemini-cli, …), the credential type (OAuth or API key), and the secret payload. OAuth rows carry both the long-lived refresh token and the short-lived access token; refreshes happen in-process whenever the access token is within a minute of expiry. API-key rows hold the raw key.

Protect the file the way you would ~/.ssh/id_*: filesystem permissions are the only thing between an attacker with read access to your home directory and your tokens. If that worries you, move the credentials off the machine entirely with the auth broker — laptops then hold no refresh tokens at all.

Signing in and out

Inside omp:

  • /login opens the provider picker. Pick a provider, complete the OAuth flow in your browser, and the resulting tokens are appended to agent.db. Pasting an API key when prompted does the same thing for non-OAuth providers.

  • /logout <provider> deletes every credential row for that provider. Use it to revoke an account without touching others.

  • To rotate, /logout then /login again. There is no in-place rotation — the new tokens replace the old row.

OAuth flows bind a local callback port per provider so the browser can hand the code back to omp. The defaults: Anthropic 54545, OpenAI Codex 1455, Google Gemini CLI 8085, Google Antigravity 51121, GitLab Duo 8080. If one is busy, close whatever else is bound to it before re-running /login.

The picker is also the inspection surface: it shows every provider with at least one row in agent.db, so a glance at /login tells you what you are currently signed into. See Providers for the OAuth-capable provider matrix.

API keys vs stored credentials

When omp needs a credential for a provider, it walks this list and returns the first hit:

  1. --api-key on the omp command line.

  2. Stored API-key row in agent.db.

  3. Stored OAuth row in agent.db (refreshed if expiring).

  4. Provider env var (ANTHROPIC_API_KEY, OPENAI_API_KEY, GEMINI_API_KEY, …).

Env vars are a fallback, not an override — a stored credential always wins over an env var for the same provider. To force the env var to take precedence, /logout <provider> first. The full env inventory lives in Environment variables.

One narrow override exists: a models.yml apiKey will beat a stored OAuth token without overriding a runtime --api-key. This is the escape hatch for “I want this one model config to use a specific key while leaving my OAuth login intact”.

Sharing credentials across machines

omp auth-broker serve turns one host into a credential vault that other machines query over HTTP. The broker is the only writer of refresh tokens; clients receive a snapshot in which refresh tokens are replaced by a sentinel, and they call back to the broker on access-token expiry.

# on the broker host
omp auth-broker serve --bind=0.0.0.0:8765
omp auth-broker login anthropic     # OAuth flow runs here
omp auth-broker token --json        # mint the bearer token for clients

Point clients at it with OMP_AUTH_BROKER_URL and OMP_AUTH_BROKER_TOKEN (or the matching auth.broker.url / auth.broker.token keys in config.yml). When set, omp bypasses the local agent.db entirely and resolves every credential through the broker. /login and /logout proxy through too, so day-to-day usage is unchanged.

omp auth-broker login <provider> --via=user@host is the trick for laptops without a browser on the broker host: it opens an SSH tunnel so the OAuth callback hits your local browser while the credential lands in the broker’s agent.db. Other useful subcommands: omp auth-broker logout <provider> (interactive without an arg), omp auth-broker list to enumerate supported providers, omp auth-broker status, omp auth-broker token --regenerate to rotate the bearer.

Transport security between client and broker is your responsibility — terminate TLS at a reverse proxy, or put the broker behind Tailscale / WireGuard. The broker enforces a bearer token on every endpoint except /v1/healthz.

Routing provider calls through the gateway

The broker only resolves credentials; it does not proxy provider traffic. For clients that speak raw OpenAI Chat, Anthropic Messages, or OpenAI Responses wire formats — third-party CLIs, scripts, IDE plugins, containerised omp — pair the broker with omp auth-gateway serve. The gateway accepts those requests on 127.0.0.1:4000 (default), strips the inbound Authorization header, asks the broker to resolve the right credential for the requested model, and forwards the bytes upstream with the resolved access token injected.

The gateway is itself a broker client, so it inherits OMP_AUTH_BROKER_URL and OMP_AUTH_BROKER_TOKEN. Its own inbound bearer token lives at ~/.omp/auth-gateway.token (mode 0600); --no-auth disables that check for loopback-only use. Clients never see provider tokens, and credential rotation continues to flow from a single broker.

  • Providers — OAuth-capable provider list and the full credential resolution order.

  • Environment variables — every OMP_* and provider *_API_KEY variable omp reads.

  • MCP — MCP servers reuse the same agent.db for their OAuth credentials.\n

Ask Docs

AI assistant to help answer questions about the documentation. Answers are read-only and cite docs/source.

Hi! How can I help you with the documentation today? Answers are read-only and cite docs/source.

Ctrl+Enter to send