feat(azure): support Entra ID bearer token auth via AZURE_OPENAI_AD_TOKEN#9716
Conversation
…OKEN In enterprise deployments only a short-lived Azure OpenAI access token is exposed to the runtime, while Azure credentials stay in a backend service. The Azure OpenAI provider previously supported only API keys or acquiring its own token through the Azure CLI credential chain. Add a BearerToken credential variant populated from the optional AZURE_OPENAI_AD_TOKEN config key. When set, the token is sent directly as 'Authorization: Bearer <token>' and Azure CLI / token acquisition is skipped. Precedence: AD token > API key > credential chain. Fixes aaif-goose#9548 Signed-off-by: hammadxcm <hammadkhanxcm@gmail.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a486e10ceb
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
|
||
| 1. **API Key Authentication** - Uses the `AZURE_OPENAI_API_KEY` for direct authentication | ||
| 2. **Azure Credential Chain** - Uses Azure CLI credentials automatically without requiring an API key | ||
| 1. **Entra ID Bearer Token** - Uses a pre-acquired Microsoft Entra access token from `AZURE_OPENAI_AD_TOKEN`, sent as `Authorization: Bearer <token>`. goose skips Azure CLI and token acquisition entirely, which suits enterprise deployments where only short-lived tokens are exposed to the runtime (e.g. obtained via `az account get-access-token --resource https://cognitiveservices.azure.com`) |
There was a problem hiding this comment.
Extract only the accessToken value in the example
When users populate the variable through command substitution from this example, az account get-access-token defaults to JSON containing accessToken, expiry, tenant, and other fields, so goose sends that entire JSON document as the bearer credential and authentication fails. The Azure CLI documentation confirms that the default output is JSON and supports --query and TSV output; show an extraction such as --query accessToken --output tsv so the documented command produces the value expected by AZURE_OPENAI_AD_TOKEN.
Useful? React with 👍 / 👎.
The az CLI outputs a JSON document by default, so command substitution from the previous example would set AZURE_OPENAI_AD_TOKEN to the whole JSON instead of the token value. Signed-off-by: hammadxcm <hammadkhanxcm@gmail.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: ba193b5a7e
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| ConfigKey::new("AZURE_OPENAI_DEPLOYMENT_NAME", true, false, None, true), | ||
| ConfigKey::new("AZURE_OPENAI_API_VERSION", false, false, None, false), | ||
| ConfigKey::new("AZURE_OPENAI_API_KEY", false, true, Some(""), true), | ||
| ConfigKey::new("AZURE_OPENAI_AD_TOKEN", false, true, Some(""), false), |
There was a problem hiding this comment.
Expose the Entra token in the setup catalog
Marking this key non-primary prevents it from appearing in ACP/native configuration flows: setup_entry_from_metadata in crates/goose-providers/src/canonical/catalog.rs builds fields using only keys where key.primary is true. Consequently those clients cannot enter the new token at all, and the newly added AZURE_OPENAI_AD_TOKEN field override is unreachable there. Make the token primary or extend the setup catalog to expose alternative/advanced authentication fields.
Useful? React with 👍 / 👎.
The setup catalog and ACP/native configuration flows only surface config keys with primary set, so the field (and its curated label) was unreachable in those clients. The key remains optional and secret, so it renders as an optional masked field. Signed-off-by: hammadxcm <hammadkhanxcm@gmail.com>
Signed-off-by: Douwe M Osinga <douwe@sidewalklabs.com>
DOsinga
left a comment
There was a problem hiding this comment.
Thanks for the contribution! This cleanly adds Entra ID bearer token auth via AZURE_OPENAI_AD_TOKEN, follows the existing credential pattern, has meaningful tests, and addresses both codex comments. I pushed a small follow-up renaming the docs section heading to cover all three auth methods. LGTM.
* main: (66 commits) feat: implement acp method for elicitation and elicitation improvement (#9797) fix: removed window goosed when closing window (#9818) View json (#9678) Make the context exceeded checker more precise (#9831) feat: load global hints from ~/.agents/AGENTS.md (#9736) fix: inherit login-shell PATH in spawned subagents (#9737) feat(gym): make per-agent timeout configurable (GYM_AGENT_TIMEOUT) (#9791) fix: accept string values for GOOSE_CONTEXT_LIMIT (#9738) feat(azure): support Entra ID bearer token auth via AZURE_OPENAI_AD_TOKEN (#9716) fix: clear rejected OAuth credentials after refresh (#9694) use windows-2022 image for CUDA builds (#9834) fix: keep extended thinking within the Anthropic output cap (#9814) fix(packaging): disable RPM build-id links (#9671) fix(providers/openai): preserve custom API path in base_url derivation (#9649) feat(i18n): language selection feature (#9405) fix(desktop): handle resume deep links (#9298) feat: added _meta.conversationBefore for ACP forking session (#9821) chore(deps): bump shlex from 1.3.0 to 2.0.1 (#9505) chore(deps): bump actions/deploy-pages from 4.0.5 to 5.0.0 (#9499) chore(deps): bump actions/upload-pages-artifact from 4.0.0 to 5.0.0 (#9497) ...
Summary
Fixes #9548
In enterprise deployments (e.g. hosted VS Code / code-server), only a short-lived Azure OpenAI access token is exposed to the runtime, while Azure credentials (client ID, secret, tenant) stay in a backend service. The Azure OpenAI provider previously supported only API keys or acquiring its own token through the Azure CLI credential chain, so this deployment pattern wasn't possible.
Changes
BearerTokenvariant toAzureCredentials, populated from a new optional secret config keyAZURE_OPENAI_AD_TOKEN(works from env var or config.yaml, same as the API key).Authorization: Bearer <token>and Azure CLI / token acquisition is skipped entirely — no caching, no subprocess.AZURE_OPENAI_AD_TOKEN>AZURE_OPENAI_API_KEY> Azure credential chain (the AD token is short-lived and explicitly injected, so setting it signals intent). Documented in the provider docs.documentation/docs/getting-started/providers.md(provider table + the Azure OpenAI auth section, now listing all three methods and their precedence).Behavior is unchanged when the new variable is unset (empty values are filtered, matching the
AWS_BEARER_TOKEN_BEDROCKpattern).Testing
azureauth.rs: credential selection precedence (token > key > default chain) andget_token()returning the bearer token without invoking the Azure CLI.azure.rs: auth header isAuthorization: Bearer <token>for the bearer path andapi-keyfor the API key path.cargo fmt,cargo clippy --all-targets -- -D warnings(withaws-providers), andcargo test -p goose providers::azure(7/7 passing) all clean.Manual verification of the token flow matches the issue author's setup: a token from
az account get-access-token --resource https://cognitiveservices.azure.complaced inAZURE_OPENAI_AD_TOKENauthenticates directly.