Skip to main content
praisonai auth stores provider credentials locally so praisonai run works without exporting env vars every session. Two methods are supported: a long-lived API key, or a short-lived OAuth token signed in via your browser.

Quick Start

The picker is built from ModelCatalogue.list_providers(): openai, anthropic, google, ollama first, every other catalogue provider (Groq, OpenRouter, Mistral, DeepSeek, xAI, …) next, and custom last.

Commands

auth login now accepts an optional provider. Run praisonai auth login with no argument to pick from a catalogue-driven list (any provider ModelCatalogue knows about — Groq, OpenRouter, Mistral, DeepSeek, xAI, …); curated providers appear first, custom last. Scripts that pass the provider positionally still work unchanged. A one-line “Get your key” hint prints before the masked prompt for well-known providers.

Login flags

Which --method should I use?

--method auto on a registry provider without a --client-id prints an info line telling you how to switch to OAuth explicitly, then falls back to the API-key prompt.

Provider Picker

Omit the provider argument and auth login opens a catalogue-driven picker so you never have to memorise a provider id.
The list comes from ModelCatalogue.list_providers(): openai, anthropic, google, ollama first, every other catalogue provider appended, custom last. Picking custom prompts for a free-form provider id. The positional <provider> argument still works unchanged — keep passing it in scripts and CI.

OAuth Login (browser-based)

Two flows are negotiated automatically per provider:
  • Device code (RFC 8628) — prints a short code + URL, polls until you approve. Default on headless servers.
  • Authorization code + PKCE (RFC 7636) — opens your default browser and listens on 127.0.0.1 for the redirect. Default on desktops.
Built-in providers ship with endpoints but no client_id (registration-specific). Supply your OAuth app’s id via --client-id; the CLI resolves the rest.
The OAuth callback handler and PKCE helpers are shared with the MCP OAuth integration.

Token storage & refresh

Self-hosted / custom OAuth providers

praisonai auth login ships built-in endpoints for github, google, gemini, and azure. For a provider outside the registry (e.g. a self-hosted gateway), supply the endpoints directly with CLI flags:
The CLI infers the device flow when a --device-authorization-url is present, or falls back to authcode (PKCE) when you pass --authorization-url instead. As an escape hatch, you can also register a provider config from Python before invoking the flow:

Headless / SSH

API Key Login

auth login (and setup) print a Get your key: link to the provider’s key-creation page before the hidden prompt for catalogue providers, so first-run users don’t have to guess where to find one:
The link comes from a static PROVIDER_KEY_URLS map (key_url_for_provider()). Providers without a mapped URL skip the hint silently.

List & status

Logout

List & Status — new columns

Source shows where the live credential comes from: stored (from ~/.praisonai/credentials.json) or env (VARNAME) when an active environment variable is present. An env key that shadows a stored one is flagged env (VARNAME) [live, overrides stored]. Expires shows (n/a) for API keys, 59m, 1h 23m, <1m, or expired for OAuth tokens, and (no expiry) when the provider didn’t include one.

Stored vs environment credentials

auth list and auth status surface both stored credentials (from ~/.praisonai/credentials.json) and active environment-variable keys for catalogue-known providers. The Source column disambiguates them: When PRAISONAI_AUTH_CONTENT is set, every stored-side entry reports env (in-memory) instead of stored:
If both a stored and an env credential exist for one provider, the env value wins at run time (this is unchanged) — the Source line appends [live, overrides stored] so it’s visible:
Both stored and env secrets are redacted the same way (sk-1***efgh).
The auth list and auth status table columns changed in this release — Method, Source, and Expires columns were added, and active env-var credentials are now surfaced. Scripts that parse the table output need to be updated. The --json output is additive only (new source / env_var keys added; no existing keys removed).

Credential env-var aliases

Some providers declare more than one credential env-var spelling — Together’s TOGETHER_API_KEY / TOGETHERAI_API_KEY, Fireworks’ FIREWORKS_API_KEY / FIREWORKS_AI_API_KEY, Google’s GOOGLE_API_KEY / GEMINI_API_KEY. auth list and auth status recognise every alias — a key set under a secondary spelling is surfaced exactly like one set under the canonical first.
The Source column names whichever alias is live in the environment, so it always tells you exactly which variable the runtime is reading — even when a secondary spelling is the one you set. If no alias is set but the provider is otherwise referenced, the canonical first var name is shown for display only.
Multi-alias recognition was fixed in PraisonAI PR #4099. Before this fix, auth list / auth status only knew the canonical first spelling for each provider and would report “not found” for a key the runtime happily accepted under a secondary alias. After the fix, auth matches runtime detection exactly.

Credential Fields (ProviderCredential)

Each stored provider credential contains the following fields: auth list and auth status show Method and Expires columns reflecting these fields.

Storage & Security

Path change — auto-migrated. Prior releases stored credentials at ~/.praison/credentials.json. The canonical path is now ~/.praisonai/credentials.json; the legacy path is still read if the canonical file doesn’t exist yet, and any subsequent auth login or setup transparently migrates your old entries onto the canonical file. No re-login is required.

Zero-disk mode (PRAISONAI_AUTH_CONTENT)

Set PRAISONAI_AUTH_CONTENT to a JSON credential store and PraisonAI runs entirely from memory — nothing is ever read from or written to ~/.praisonai/credentials.json. Use it for ephemeral containers (Docker/Kubernetes), CI runners, and secret-hygiene-sensitive deployments where OAuth and refresh tokens must not touch disk. A single secret injects the whole store — including OAuth entries — with zero on-disk footprint. The value is a JSON object mapping provider name → credential object. Each credential object mirrors the on-disk ProviderCredential fields — api_key and auth_method for API keys, plus access_token, refresh_token, and expires_at for OAuth:
Invalid values fail fast rather than silently falling back to disk, protecting the zero-disk contract:
Precedence: the env blob always wins over any on-disk credentials.json. Per-provider API-key env vars (OPENAI_API_KEY, …) still win for that specific provider at run time — unchanged.
Treat PRAISONAI_AUTH_CONTENT as a secret. Inject it only from a secrets manager, never commit it, and prefer a CI runtime that scrubs env vars from build logs. OAuth tokens refreshed in this mode stay in memory only — nothing is written back to disk.
auth list and auth status report the Source column as env (in-memory) in this mode via the CredentialStore.is_in_memory property, so zero-disk runs are never silently invisible.
Sibling for config: PRAISONAI_CONFIG_CONTENT and PRAISONAI_CONFIG do the same thing for the user-config layer. Setting both alongside PRAISONAI_AUTH_CONTENT gives you a fully zero-disk PraisonAI run. See Security Environment Variables → PRAISONAI_CONFIG_CONTENT.

Supported Providers

praisonai auth list / praisonai auth status recognise every provider in PROVIDER_ENV_CATALOGUE — the same catalogue that drives first-run credential detection (full 14-row table) and praisonai setup. Unknown providers accept API keys with length ≥ 10. OAuth is opt-in per provider; registry providers ship endpoints but no client_id — pass yours with --client-id.

Optional dependency

The OAuth flow uses the requests library. It is lazy-imported, so users on the API-key path never see it. If a user runs --method oauth without it installed:

How Run Uses Credentials

praisonai run resolves credentials in this order:
  1. Environment variables (OPENAI_API_KEY, ANTHROPIC_API_KEY, …)
  2. Stored credentials — OAuth tokens refreshed transparently (~60 s before expiry) before injection. When PRAISONAI_AUTH_CONTENT is set, this store is the in-memory env blob instead of ~/.praisonai/credentials.json, and any OAuth refresh stays in memory only
  3. LLM endpoint resolution via resolve_llm_endpoint_with_credentials

Model → provider inference

When praisonai run picks a model id from your environment (rather than a --model flag or [llm] config entry), it prints a one-line transparency notice naming the credential that drove the choice:
The notice now fires for every catalogued provider, not just the historical eight. Setting OPENROUTER_API_KEY, MISTRAL_API_KEY, DEEPSEEK_API_KEY, XAI_API_KEY, TOGETHER_API_KEY / TOGETHERAI_API_KEY, FIREWORKS_API_KEY / FIREWORKS_AI_API_KEY, PERPLEXITYAI_API_KEY, or COHERE_API_KEY all produce the notice with the alias you actually set — so you can see which key the runtime picked up before the first LLM call. For providers with multiple credential spellings, the notice names whichever alias is live in os.environ, matching the Source column of auth list.
Coverage was extended in PraisonAI PR #4099. Before this fix, _provider_for_model() silently returned None for openrouter/mistral/deepseek/xai/together/fireworks, so no transparency notice printed for those providers even when a key was set. After the fix, every catalogued provider prints the notice.
If an expired OAuth token cannot be refreshed (refresh token revoked, network error, etc.), praisonai run reports:
If nothing is found, non-interactive mode exits with:
See Run for the interactive wizard path.

Run

Preflight credential check before execution

Config

Default model via [llm] in config.toml

Setup

First-run setup wizard