opencode icon indicating copy to clipboard operation
opencode copied to clipboard

feat: add apiKeyCommand for dynamic API key retrieval

Open lars-osterberg opened this issue 2 days ago • 2 comments

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 /connect command (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_process in ~/.aws/config
  • Git: credential.helper configuration
  • Docker: credHelpers in ~/.docker/config.json

Changes

  • Added apiKeyCommand field to provider options in config schema
  • Added resolveApiKeyCommand() helper function to execute the command
  • Updated getSDK() to check for apiKeyCommand when no apiKey is set

lars-osterberg avatar Jan 13 '26 11:01 lars-osterberg