How to Configure Authentication Keys for Upstream Providers in Switchyard
Configure upstream authentication in Switchyard by referencing environment variables in your TOML configuration rather than embedding secrets directly.
Switchyard, an open-source LLM routing layer from NVIDIA, handles authentication through environment variable references in deployment configuration files. This design keeps API keys out of version control while supporting flexible authentication patterns—from single static keys to per-call credential forwarding.
Understanding the Two-Layer Authentication Model
The authentication flow in Switchyard operates across two distinct layers: the native server configuration and launcher-specific overrides. Understanding this separation helps you choose the right approach for your deployment.
Layer 1: TOML Deployment Configuration
Each upstream provider is defined under the [llm_clients] table in your routes.toml. The critical field is api_key_env, which specifies the name of the environment variable containing the actual key—not the key itself.
In docs/reference/toml_schema.md (lines 41–48), the schema defines this behavior:
api_key_env= environment variable name to read at startup- If omitted, requests are sent without any authentication header
forward_auth= boolean to forward the caller's credentials instead
Layer 2: Launcher-Specific Overrides
When Switchyard launches clients like Codex or Claude Code, it constructs transient provider configurations that override or supplement the TOML settings.
In switchyard/cli/launchers/codex_cli_launcher.py (lines 78–90), the _provider_overrides dictionary is built with conditional logic:
requires_openai_authflag controls whether a key is injectedenv_keypoints to "OPENAI_API_KEY" when credential forwarding is desired_codex_env(lines 97–102) setsOPENAI_API_KEY="switchyard"as a fallback
For Claude Code, switchyard/cli/launchers/claude_code_launcher.py (lines 70–92) demonstrates a different pattern: ANTHROPIC_API_KEY="" suppresses conflict warnings while routing through the proxy.
Configuration Methods for Different Use Cases
Static Server-Owned Key (Most Common)
Use this pattern when the Switchyard server owns a single credential for an upstream provider.
Step 1: Define the environment variable name in your TOML:
[llm_clients.openai]
base_url = "https://api.openai.com/v1"
api_key_env = "OPENAI_API_KEY"
model = "gpt-4o"
Step 2: Export the actual key before starting Switchyard:
export OPENAI_API_KEY="sk-..."
switchyard-server --config routes.toml
The native server reads docs/reference/toml_schema.md, resolves api_key_env to the concrete value, and injects the Authorization: Bearer ... header on every request.
Forward Caller's Credential (Multi-Tenant)
Use this pattern when each user presents their own API key and you want to proxy requests without server-side authentication.
[llm_clients.openai]
base_url = "https://api.openai.com/v1"
forward_auth = true
# api_key_env intentionally omitted
With forward_auth = true, Switchyard forwards the caller's Authorization header—or provider-specific headers like X-API-Key—to the upstream unchanged. This enables multi-tenant deployments where the server never handles raw credentials.
Testing with Launcher-Provided Keys (Local Development)
Launchers automatically inject synthetic keys when appropriate, keeping secrets out of configuration during testing.
Codex CLI pattern (switchyard/cli/launchers/codex_cli_launcher.py):
# When forward_auth is disabled, inject placeholder
_codex_env["OPENAI_API_KEY"] = "switchyard"
Claude Code pattern (switchyard/cli/launchers/claude_code_launcher.py):
_claude_env["ANTHROPIC_API_KEY"] = "" # Silences conflict warning
These defaults allow local testing against rate-limited internal services that require a key without exposing actual credentials.
Provider-Specific Environment Variables
Switchyard supports any provider following the Bearer token convention. Common variable names as implemented in the_source code:
| Provider | Typical api_key_env Value |
Header Format |
|---|---|---|
| OpenAI | OPENAI_API_KEY |
Authorization: Bearer sk-... |
| Anthropic | ANTHROPIC_API_KEY |
x-api-key: sk-ant-... |
| OpenRouter | OPENROUTER_API_KEY |
Authorization: Bearer sk-or-... |
| NVIDIA | NVIDIA_API_KEY |
Authorization: Bearer nvapi-... |
The exact variable name is user-defined in api_key_env—Switchyard does not enforce provider-specific conventions.
Where Keys Are Consumed in the Codebase
| File Path | Authentication Role |
|---|---|
docs/reference/toml_schema.md |
Defines TOML schema including api_key_env and forward_auth |
switchyard/cli/launchers/native_server.py |
Starts server that reads TOML and resolves environment variables |
switchyard/cli/launchers/codex_cli_launcher.py |
Constructs _provider_overrides with env_key and "switchyard" fallback |
switchyard/cli/launchers/claude_code_launcher.py |
Builds _claude_env with empty ANTHROPIC_API_KEY workaround |
Common Configuration Pitfalls
Mistake: Embedding the key directly
# WRONG - never do this
api_key_env = "sk-live-actual-key"
The api_key_env field expects a variable name, not the key value. Embedding secrets exposes credentials in logs and version control.
Mistake: Setting both api_key_env and forward_auth
# Undefined behavior - choose one pattern
api_key_env = "OPENAI_API_KEY"
forward_auth = true
These options are mutually exclusive. The server uses api_key_env if present; forward_auth only applies when api_key_env is absent.
Summary
- Never embed secrets in TOML files—use
api_key_envto reference environment variables - Export variables before launching:
export PROVIDER_API_KEY="..." - Use
forward_auth = truefor multi-tenant credential forwarding instead of server-side keys - Rely on launcher defaults (
"switchyard", empty strings) for local testing without real credentials - Verify in source:
docs/reference/toml_schema.mddefines the schema; launcher files show override behavior
Frequently Asked Questions
What happens if I omit api_key_env entirely?
Requests to that provider are sent without any authentication header. This works for open endpoints or when using forward_auth = true to pass through caller credentials. Per the TOML schema (docs/reference/toml_schema.md, lines 41–48), the field is optional and defaults to no authentication.
Can I use the same environment variable for multiple providers?
Yes. Multiple [llm_clients.<name>] sections can reference the same api_key_env value. However, best practice is using provider-specific variables (e.g., OPENAI_API_KEY, ANTHROPIC_API_KEY) to enable credential rotation per service without affecting others.
How do I rotate credentials without restarting Switchyard?
You must restart the native server. Environment variables are read once at startup in switchyard/cli/launchers/native_server.py. There is no hot-reload mechanism for authentication configuration. For zero-downtime rotation, deploy a new instance with updated variables and migrate traffic.
Why does Claude Code use an empty ANTHROPIC_API_KEY?
As implemented in switchyard/cli/launchers/claude_code_launcher.py (lines 70–92), the empty string suppresses a conflict warning from Claude Code's internal validation. The actual request routing goes through Switchyard's proxy, so the upstream never receives the empty value—authentication is handled by the proxy configuration instead.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →