feat(auth): enable refresh auth cli (#11657)

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Leon Bowie
2026-09-01 01:42:11 +00:00
committed by GitHub
parent 35897f6984
commit 0a9749b1cb
19 changed files with 985 additions and 21 deletions
@@ -465,7 +465,9 @@ Custom providers must use OpenAI, Anthropic, or Ollama compatible API formats. T
- **Name**: A friendly name for the provider
- **API URL**: The base URL of the API endpoint
- **Authentication Required**: Answer "Yes" if your provider needs an API key, or "No" if authentication is not required
- If Yes: You'll be prompted to enter your **API Key** (stored securely in the keychain, or in `secrets.yaml` if the keyring is disabled or cannot be accessed)
- If Yes: Choose how goose should obtain the credential:
- **Static API key**: You'll be prompted to enter your **API Key** (stored securely in the keychain, or in `secrets.yaml` if the keyring is disabled or cannot be accessed)
- **Command (refreshable)**: You'll be prompted for a **command** (and optional arguments) that goose runs to fetch the credential, plus a **refresh interval** in seconds. Use this for short-lived credentials issued by an IdP or key vault, so goose can refresh them automatically instead of requiring a restart when they expire. See [Command-Based Authentication](#command-based-authentication) below.
- If No: The API key prompt is skipped
- **Available Models**: Comma-separated list of available model names
- **Streaming Support**: Whether the API supports streaming responses
@@ -523,6 +525,50 @@ Custom providers must use OpenAI, Anthropic, or Ollama compatible API formats. T
</TabItem>
</Tabs>
### Command-Based Authentication
Instead of a static `api_key_env`, a custom provider can be configured to run a command to obtain its credential. This is useful for short-lived credentials issued by an IdP or key vault: goose re-runs the command to refresh the credential instead of requiring a restart when it expires.
Add an `auth` object to the provider's JSON configuration in place of `api_key_env` (the two are mutually exclusive):
```json
{
"name": "custom_corp_api",
"engine": "openai",
"display_name": "Corporate API",
"base_url": "https://api.company.com/v1/chat/completions",
"models": [{ "name": "gpt-4o", "context_limit": 128000 }],
"requires_auth": true,
"auth": {
"command": "/path/to/get-token.sh",
"args": [],
"refresh_interval": 3600,
"timeout_seconds": 10
}
}
```
- **`command`**: The executable to run. It is spawned directly, without a shell — none of `command`/`args` are shell-interpolated. If your script needs shell features (pipes, variable expansion), invoke an interpreter explicitly, e.g. `"command": "/bin/bash", "args": ["-c", "..."]`. A bare name (no path separator, e.g. `"get-token"`) is looked up on `PATH`; a relative path (e.g. `"./scripts/get-token.sh"`) is resolved against `cwd`.
- **`args`** (optional): Arguments passed to `command`.
- **`refresh_interval`** (optional, defaults to `3600`): How long, in seconds, a fetched credential is cached before the command is re-run. Set to `0` to disable proactive refresh entirely — the command then only reruns reactively, after the provider's API rejects a request with an auth error.
- **`timeout_seconds`** (optional, defaults to `10`): How long to wait for the command before treating it as failed.
- **`cwd`** (optional): Working directory for the command, and the base a relative `command` path is resolved against. Defaults to goose's current directory.
The command's trimmed standard output is used as the credential. It must exit successfully and print a non-empty value; on failure, goose surfaces an error rather than silently reusing a stale credential. The command inherits goose's full environment, since the same user configures goose and writes the script.
<Tabs groupId="interface">
<TabItem value="cli" label="goose CLI" default>
In `goose configure`, choose **Command (refreshable)** when prompted for how to obtain credentials for a custom provider (see [above](#configure-custom-provider)).
</TabItem>
<TabItem value="config" label="Config File">
Add the `auth` object shown above to the provider's JSON file instead of setting `api_key_env`.
</TabItem>
</Tabs>
**To update a custom provider:**
<Tabs groupId="interface">