opencode
opencode copied to clipboard
feat: add apiKeyCommand for dynamic API key retrieval
Summary
Add support for fetching API keys dynamically by executing a command. This enables integration with credential managers, token services, or any external authentication system.
Related Issues
This PR addresses several feature requests from the community:
- #1302 - Request to support Dynamic API keys through an apiKeyHelper (LiteLLM proxy with rotating tokens)
- #7487 - exec variable substitution (1Password CLI integration)
- #231 - add ability to load secrets from external command or environment variables
- #4318 - Allow storage of secrets in system credential store
Motivation
Currently, API keys can be provided via:
- Static values in the config file
- Environment variables using
{env:VAR_NAME}syntax - The
/connectcommand (stored in auth.json)
This works well for simple setups, but doesn't support:
-
Credential helpers that fetch tokens dynamically (similar to git's
credential.helper) - Token services like LiteLLM proxy servers that require short-lived tokens
- Secret managers (1Password CLI, AWS Secrets Manager, HashiCorp Vault, etc.)
- Desktop apps that can't inherit environment variables from shell wrappers
Usage
{
"provider": {
"my-provider": {
"options": {
"apiKeyCommand": ["my-credential-helper", "get-token"]
}
}
}
}
The command should output the API key to stdout. The output is trimmed of whitespace.
Examples
// 1Password CLI
{
"provider": {
"openai": {
"options": {
"apiKeyCommand": ["op", "read", "op://Private/OpenAI/api-key"]
}
}
}
}
// Custom token service (e.g., LiteLLM with IDP auth)
{
"provider": {
"my-llm-proxy": {
"options": {
"apiKeyCommand": ["my-auth-cli", "get-token"]
}
}
}
}
// AWS Secrets Manager
{
"provider": {
"openai": {
"options": {
"apiKeyCommand": ["aws", "secretsmanager", "get-secret-value", "--secret-id", "openai-key", "--query", "SecretString", "--output", "text"]
}
}
}
}
Design Notes
This complements the existing {env:VAR_NAME} syntax rather than replacing it. The apiKeyCommand approach is:
- Explicit: Only used for API keys, not arbitrary config values
- Secure: Command is executed at SDK initialization time, not config parse time
- Flexible: Supports any command that outputs a token to stdout
An alternative approach would be adding {exec:command} syntax similar to {env:...}, but apiKeyCommand is more targeted and follows patterns used by:
- AWS CLI:
credential_processin~/.aws/config - Git:
credential.helperconfiguration - Docker:
credHelpersin~/.docker/config.json
Changes
- Added
apiKeyCommandfield to provider options in config schema - Added
resolveApiKeyCommand()helper function to execute the command - Updated
getSDK()to check forapiKeyCommandwhen noapiKeyis set