JuliusBrussee/caveman · error
azure bearer credentials are unsupported; use an API key
Error message
azure bearer credentials are unsupported; use an API key
What it means
Azure OpenAI auth in this adapter supports only API keys (mapped to the api-key header). A credential whose scheme is bearer, whose value starts with 'Bearer ' or looks like a JWT ('eyJ...') is rejected outright: relabeling an Entra token as an api-key would silently fail auth upstream, so the adapter fails closed until bearer auth is properly supported. The synthetic 'no-key-required' marker is explicitly exempted.
Source
Thrown at proxy/providers/adapter.go:504
out.Set("authorization", "Bearer "+credential.Key)
}
copyIfPresent(out, req.Header, "x-vertex-ai-llm-request-type")
copyIfPresent(out, req.Header, "x-goog-user-project")
case "azure_openai":
if credential.Key != "" {
// The standalone placeholder is a synthetic no-key marker used by
// callers that explicitly allow env-backed API-key fallback. It is
// not an Entra token and must not be forwarded as Authorization;
// gateway fallback may replace it with the Azure api-key header.
if credential.Scheme == "bearer" && credential.Key == "no-key-required" {
break
}
// Real bearer/JWT credentials remain fail-closed until an auth-kind is
// persisted and mapped end-to-end. They must never be silently
// relabeled as an api-key.
fields := strings.Fields(strings.TrimSpace(credential.Key))
if credential.Scheme == "bearer" || len(fields) > 1 && strings.EqualFold(fields[0], "bearer") || strings.HasPrefix(strings.TrimSpace(credential.Key), "eyJ") {
return nil, fmt.Errorf("azure bearer credentials are unsupported; use an API key")
}
out.Set("api-key", credential.Key)
}
default:
if credential.Key != "" {
out.Set("authorization", "Bearer "+credential.Key)
}
}
return out, nil
}
func validGoogleQuotaProject(value string) bool {
if value == "" || len(value) > 128 {
return false
}
for _, r := range value {
if r >= 'a' && r <= 'z' || r >= 'A' && r <= 'Z' || r >= '0' && r <= '9' || r == '-' || r == '.' || r == '_' || r == ':' {
continueView on GitHub (pinned to 27d5a3981a)
Solutions
- Use an Azure OpenAI API key for this provider: generate one in the Azure OpenAI resource (Keys and Endpoint) and configure it as the api-key credential.
- Strip any 'Bearer ' prefix or scheme metadata so the stored secret is the bare key value.
- Do not feed az account get-access-token output here — Entra bearer auth is deliberately unsupported.
Example fix
# before
providers:
azure:
credential_scheme: bearer
key: eyJhbGciOiJSUzI1NiIs... # Entra JWT -> error
# after
providers:
azure:
key: 32charAzureOpenAIResourceKey # from Keys and Endpoint blade Defensive patterns
Strategy: validation
Validate before calling
func isAzureAPIKeyCredential(scheme, key string) bool {
if scheme == "bearer" {
return false
}
fields := strings.Fields(strings.TrimSpace(key))
if len(fields) > 1 && strings.EqualFold(fields[0], "bearer") {
return false
}
return !strings.HasPrefix(strings.TrimSpace(key), "eyJ")
}
if !isAzureAPIKeyCredential(cred.Scheme, cred.Key) {
return errors.New("Azure provider requires an API key, not an Entra/JWT token")
} Type guard
func isAzureAPIKeyCredential(scheme, key string) bool {
if scheme == "bearer" {
return false
}
fields := strings.Fields(strings.TrimSpace(key))
if len(fields) > 1 && strings.EqualFold(fields[0], "bearer") {
return false
}
return !strings.HasPrefix(strings.TrimSpace(key), "eyJ")
} Try / catch
if _, err := adapter.BuildUpstreamHeaders(credential, req); err != nil {
if strings.Contains(err.Error(), "azure bearer credentials are unsupported") {
http.Error(w, "configure an Azure OpenAI API key for this provider", http.StatusBadRequest)
return
}
http.Error(w, err.Error(), http.StatusBadRequest)
} Prevention
- Provision Azure OpenAI resource keys and store the bare key value.
- Never feed az account get-access-token output to this provider.
- Secrets managers should store the raw key without scheme prefixes.
When it happens
Trigger: Configuring the Azure provider with credential_scheme: bearer; pasting an Entra ID / Azure AD token (they start with eyJ) into the api-key field; injecting OAuth credentials from a vault that prefixes values with 'Bearer '.
Common situations: Porting config from a tool that uses Azure AD auth (azure-cli login, managed identity) and assuming the same token works here; secrets managers that store tokens with their scheme prefix; copy-pasting a JWT from an Entra token dump.
Related errors
- Claude usage refresh needs CAVEMAN_CLAUDE_USAGE_JSON or CAVE
- azure api-version %q is not on the allowlist
- cachebench: no providers
- cachebench: provider population exceeds 1024
- cachebench: invalid observation read limits
AI-assisted analysis of JuliusBrussee/caveman@27d5a3981a (2026-08-15).
Data as JSON: /api/errors/e7d6148918d8372a.
Report an issue: GitHub.