Authentication matrix

August 3, 2026 · View on GitHub

This document describes every authentication combination supported by AWF's api-proxy sidecar, including how each provider's auth works, what configuration is required, and how the proxy transforms credentials before forwarding to upstream APIs.

The Auth Doctor Updater workflow periodically compares this matrix with current default-branch implementation, recent issues and pull requests, and official provider guidance. It opens a deduplicated, file-bounded pull request only when an evidence-backed documentation correction is needed.

Table of Contents


Dimensions Overview

Auth evaluation in the api-proxy is determined by the combination of these independent axes:

#DimensionControlled ByValues
1EnginePort binding (10000–10004)openai, anthropic, copilot, gemini, vertex
2Auth TypeAWF_AUTH_TYPEapi-key (default), github-oidc
3OIDC ProviderAWF_AUTH_PROVIDERazure, aws, gcp, anthropic
4Instance TypeGITHUB_SERVER_URLgithub.com, GHEC (*.ghe.com), GHES
5BYOK ModeCOPILOT_PROVIDER_TYPEunset (standard), azure
6Target Override{PROVIDER}_API_TARGETAny hostname
7Custom Auth HeaderAWF_{PROVIDER}_AUTH_HEADERAny valid HTTP header name
8Extra InjectionAWF_BYOK_EXTRA_HEADERS, AWF_BYOK_EXTRA_BODY_FIELDSJSON objects

:::note The OIDC Provider dimension (AWF_AUTH_PROVIDER) only applies to the OpenAI, Anthropic, and Copilot adapters. The Gemini and Vertex adapters are static-API-key only in the current implementation — see Provider: Google Vertex AI for how GCP workload identity federation reaches Vertex-compatible endpoints today. :::


Provider: OpenAI

Port: 10000
Implementation: containers/api-proxy/providers/openai.js

Static API Key

SettingValue
Env varOPENAI_API_KEY
Header sent upstreamAuthorization: Bearer <key>
Default targetapi.openai.com
Default base path/v1

Official docs: https://platform.openai.com/docs/api-reference/authentication

Azure OpenAI (BYOK via Copilot)

When COPILOT_PROVIDER_TYPE=azure and COPILOT_PROVIDER_BASE_URL is set:

SettingValue
Env varCOPILOT_PROVIDER_API_KEY
Header sent upstreamapi-key: <key> (NOT Authorization:)
TargetDerived from COPILOT_PROVIDER_BASE_URL
Base pathDerived from URL path component

Official docs: https://learn.microsoft.com/en-us/azure/foundry/openai/reference

Azure OIDC (Entra ID)

When AWF_AUTH_TYPE=github-oidc and AWF_AUTH_PROVIDER=azure:

SettingValue
Header sent upstreamAuthorization: Bearer <token>
Token exchangeGitHub JWT → Azure AD token endpoint
Scopehttps://cognitiveservices.azure.com/.default (default; configurable via AWF_AUTH_AZURE_SCOPE)
OIDC audienceapi://AzureADTokenExchange (configurable via AWF_AUTH_OIDC_AUDIENCE)

Note: When Azure OIDC is active, the header switches from api-key: back to Authorization: Bearer.

:::note[Implementation vs. provider documentation] https://cognitiveservices.azure.com/.default is AWF's hardcoded default scope and remains valid for Azure OpenAI/Foundry resources. Some newer Microsoft Foundry how-to guides show https://ai.azure.com/.default for certain data-plane operations — this is not a universal replacement, and either value may be required depending on your resource and API surface. Set AWF_AUTH_AZURE_SCOPE (or apiProxy.auth.azureScope) explicitly if your deployment needs a different scope; AWF does not infer the correct scope for you. :::

Official docs: https://learn.microsoft.com/en-us/azure/foundry-classic/openai/how-to/managed-identity

:::note[Implementation vs. provider documentation] OpenAI's own API now offers native workload identity federation, which exchanges an external OIDC/JWT identity at https://auth.openai.com/oauth/token for a short-lived OpenAI access token. AWF does not implement this. The openai.js adapter's AWF_AUTH_PROVIDER OIDC support (azure, aws, gcp) is for reaching Azure OpenAI/Foundry or GCP-fronted OpenAI-compatible endpoints using that cloud's own identity tokens — it is unrelated to OpenAI's native federation feature. :::

Custom Auth Header

AWF_OPENAI_AUTH_HEADER overrides the header name used for the API key. The raw key or token value is sent directly as the header value (no Bearer prefix is added), both for static keys and OIDC tokens.


Provider: Anthropic

Port: 10001
Implementation: containers/api-proxy/providers/anthropic.js

Static API Key

SettingValue
Env varANTHROPIC_API_KEY
Header sent upstreamx-api-key: <key>
Default targetapi.anthropic.com
Default base path(none)

Additional required headers: anthropic-version: 2023-06-01

Official docs: https://platform.claude.com/docs/en/api/overview

:::note[Implementation vs. provider documentation] Anthropic SDKs officially support ANTHROPIC_AUTH_TOKEN for bearer-token authentication. AWF does not currently accept that variable as a host-side source credential: static Anthropic auth is read from ANTHROPIC_API_KEY and sent as x-api-key. In the agent container, AWF reserves ANTHROPIC_AUTH_TOKEN for the non-secret placeholder sk-ant-placeholder-key-for-credential-isolation; the real credential remains in the sidecar. :::

Workload Identity Federation (WIF)

When AWF_AUTH_TYPE=github-oidc and AWF_AUTH_PROVIDER=anthropic:

SettingValue
Header sent upstreamAuthorization: Bearer <wif_token> (NOT x-api-key)
Token exchange endpointPOST https://api.anthropic.com/v1/oauth/token
Grant typeurn:ietf:params:oauth:grant-type:jwt-bearer
Required configAWF_AUTH_ANTHROPIC_FEDERATION_RULE_ID, AWF_AUTH_ANTHROPIC_ORGANIZATION_ID, AWF_AUTH_ANTHROPIC_SERVICE_ACCOUNT_ID
Optional configAWF_AUTH_ANTHROPIC_WORKSPACE_ID, AWF_AUTH_ANTHROPIC_TOKEN_URL
OIDC audiencehttps://api.anthropic.com (default, configurable)
Token formatsk-ant-oat01-... (short-lived)

Key behavior change: When OIDC is active, the auth header switches from x-api-key to Authorization: Bearer.

:::note[Anthropic beta headers] AWF follows Anthropic's SDK behavior: JWT-bearer POST /v1/oauth/token exchanges send oauth-2025-04-20,oidc-federation-2026-04-01, while API requests authenticated with the resulting bearer token send oauth-2025-04-20. The federation beta is never added to static x-api-key requests or forwarded refresh-token exchanges. Client-supplied anthropic-beta values are preserved and deduplicated with AWF-required values and the optional auto-cache beta. :::

Official references: Anthropic WIF documentation · Anthropic TypeScript SDK federation exchange

Custom Auth Header

AWF_ANTHROPIC_AUTH_HEADER overrides the header name (default: x-api-key). Useful for enterprise gateways that expect a different header.


Provider: GitHub Copilot

Port: 10002
Implementation: containers/api-proxy/providers/copilot.js, containers/api-proxy/providers/copilot-auth.js

GitHub OAuth Token (Standard)

InstanceEnv varHeaderTarget
github.comCOPILOT_GITHUB_TOKENAuthorization: Bearer <token>api.githubcopilot.com
GHEC (*.ghe.com)COPILOT_GITHUB_TOKENAuthorization: Bearer <token>copilot-api.<subdomain>.ghe.com
GHES (on-prem)COPILOT_GITHUB_TOKENAuthorization: token <value> ⚠️api.enterprise.githubcopilot.com
Business tierCOPILOT_GITHUB_TOKENAuthorization: token <value> ⚠️api.business.githubcopilot.com (must be set explicitly via COPILOT_API_TARGET; never auto-derived)

:::note[Implementation vs. provider documentation] GitHub's REST API authentication docs state that Authorization: Bearer and Authorization: token are both generally accepted for PATs/OAuth tokens (only JWTs strictly require Bearer). The token prefix requirement documented here is AWF-implementation-specific defensive behavior for the Copilot chat-completions inference endpoint, not a general GitHub REST API rule: the enterprise and business Copilot targets (api.enterprise.githubcopilot.com, api.business.githubcopilot.com) return 400 Bad Request: Authorization header is badly formatted when sent Bearer instead of token (see the regression covered by copilot-adapter-enterprise.test.js). AWF detects this via copilotTargetRequiresGitHubTokenPrefix() in copilot-auth.js, which matches on the specific target hostname or GHES-detection heuristics (AWF_PLATFORM_TYPE=ghes, or a GITHUB_SERVER_URL that isn't github.com/*.ghe.com). BYOK keys always use Bearer regardless of target. :::

All Copilot requests also include Copilot-Integration-Id. The default is agentic-workflows; set COPILOT_INTEGRATION_ID to override it.

/models Endpoint (Special Case)

The /models endpoint prefers COPILOT_GITHUB_TOKEN (GitHub OAuth) over BYOK keys when both are configured, because model listing is a GitHub platform feature. However, when no GitHub token is available (typical for direct-BYOK/custom targets), /models will use the BYOK credential.

BYOK (Bring Your Own Key)

SettingValue
Env varCOPILOT_PROVIDER_API_KEY
HeaderAuthorization: Bearer <key> (always Bearer, even on GHES)
TargetFrom COPILOT_PROVIDER_BASE_URL or COPILOT_API_TARGET

Azure BYOK through the OpenAI adapter

When COPILOT_PROVIDER_TYPE=azure, the OpenAI adapter on port 10000:

  • Header switches to api-key: <value> (Azure convention)
  • Unless OIDC is active, in which case it's Authorization: Bearer

The Copilot adapter on port 10002 does not emit api-key; its BYOK requests use Authorization: Bearer.

Copilot OIDC (Azure Entra / GCP / AWS)

When AWF_AUTH_TYPE=github-oidc with Copilot:

ProviderHeaderNotes
AzureAuthorization: Bearer <entra_token>Via oidc-token-provider.js
GCPAuthorization: Bearer <gcp_token>Via gcp-oidc-token-provider.js
AWSSigV4 Authorization plus x-amz-* signing headersVia aws-oidc-token-provider.js and aws-sigv4.js

:::caution[Agent routing is credential-triggered] Cloud OIDC configuration can initialize credentials in the sidecar, but the agent's OpenAI and Copilot base URLs/placeholders are currently configured only when the corresponding static OpenAI/Copilot credential is present. Anthropic WIF is the exception: its credential environment explicitly recognizes Anthropic OIDC. Treat Azure, GCP, and AWS OIDC support as sidecar authentication capability rather than a complete keyless agent-routing path until OIDC-aware agent routing is implemented. :::

:::note[AWS OIDC + Copilot] Selecting AWF_AUTH_PROVIDER=aws signs Copilot-adapter HTTP requests at final dispatch with the cached temporary STS credentials. The target must be the exact regional Bedrock Runtime hostname; credentials are never returned by getAuthHeaders() or exposed to the agent. :::

Official docs:


Provider: Google Gemini

Port: 10003
Implementation: containers/api-proxy/providers/gemini.js

Static API Key

SettingValue
Env varGEMINI_API_KEY
Header sent upstreamx-goog-api-key: <key>
Default targetgenerativelanguage.googleapis.com
Default base path(none)

The proxy also strips ?key=, ?apiKey=, and ?api_key= query parameters from requests to prevent duplicate-key errors.

:::note The native Gemini API supports OAuth, but the AWF Gemini adapter does not — only a static GEMINI_API_KEY is supported. There are two distinct ways to reach Google infrastructure with GCP workload identity federation:

  1. Native Vertex AI adapter (port 10004, static key only) — see Provider: Google Vertex AI.
  2. OpenAI adapter with GCP OIDC — point OPENAI_API_TARGET at a Vertex AI OpenAI-compatible endpoint and set AWF_AUTH_TYPE=github-oidc, AWF_AUTH_PROVIDER=gcp. This is a separate code path (openai.js) from the native Vertex adapter and is the only way to use GCP OIDC/WIF with Vertex-hosted models today. :::

:::caution[Gemini API key migration] Google says the Gemini API will reject standard API keys beginning in September 2026. Migrate GEMINI_API_KEY to Google's service-account-bound authorization key format before that deadline; AWF forwards either key type through the same x-goog-api-key header. :::

Official docs: https://ai.google.dev/gemini-api/docs/api-key


Provider: Google Vertex AI

Port: 10004 Implementation: containers/api-proxy/providers/vertex.js (shares createGoogleApiKeyAdapter with the Gemini adapter via google-adapter.js)

Static API Key

SettingValue
Env varGOOGLE_API_KEY
Header sent upstreamx-goog-api-key: <key>
Default targetaiplatform.googleapis.com
Default base path(none)

:::caution Unlike the OpenAI, Anthropic, and Copilot adapters, the Vertex adapter does not call createOidcAwareProviderAdapter — it is always bound to port 10004 (returning 503 if GOOGLE_API_KEY is unconfigured) and supports only the static-key flow described above. There is no OIDC/WIF variant of this adapter. For GCP workload identity federation with Vertex-hosted models, use the OpenAI adapter pathway described in the Google Gemini section above instead. :::

:::note[Implementation vs. provider documentation] This adapter exists to support the Gemini CLI's GOOGLE_GENAI_USE_VERTEXAI=true mode: setting GOOGLE_VERTEX_BASE_URL to point at this sidecar lets AWF isolate whatever credential the CLI is configured to send. Google's general Vertex AI guidance recommends Application Default Credentials, a service account key, or workload identity federation for Vertex AI endpoints, and treats a bare API key as unsupported for most Vertex AI surfaces (API keys are the norm for the separate Gemini Developer API at generativelanguage.googleapis.com). AWF does not attempt to validate that aiplatform.googleapis.com accepts a given key for a given operation — it forwards x-goog-api-key unconditionally. Confirm your specific Vertex AI project/API supports API-key auth (for example, Vertex AI Express Mode) before relying on this adapter in production. :::

Official docs: https://geminicli.com/docs/get-started/authentication/


OIDC Providers

All OIDC flows require GitHub Actions runtime tokens:

  • ACTIONS_ID_TOKEN_REQUEST_URL — endpoint to mint OIDC JWTs
  • ACTIONS_ID_TOKEN_REQUEST_TOKEN — auth token for the OIDC endpoint

Documentation audits treat both as non-observable credentials: they verify id-token: write and sidecar configuration but never request or print either value, a minted JWT, or exchanged cloud credentials.

AWF forwards these variables only to the api-proxy sidecar in github-oidc mode and excludes them from the agent container. GitHub Agentic Workflows independently passes them from its runner-owned Start MCP Gateway step directly to the MCP gateway when a remote HTTP MCP server uses auth.type: github-oidc; AWF does not launch or configure that gateway. See github/gh-aw#50053 for lock-file compatibility tracking.

Azure (Entra ID)

ConfigEnv VarRequired
Tenant IDAWF_AUTH_AZURE_TENANT_ID
Client IDAWF_AUTH_AZURE_CLIENT_ID
ScopeAWF_AUTH_AZURE_SCOPE❌ (default: https://cognitiveservices.azure.com/.default)
CloudAWF_AUTH_AZURE_CLOUD❌ (default: public; options: public, usgovernment, china)
AudienceAWF_AUTH_OIDC_AUDIENCE❌ (default: api://AzureADTokenExchange)

Token exchange endpoint: https://login.microsoftonline.com/<tenant>/oauth2/v2.0/token
Implementation: containers/api-proxy/oidc-token-provider.js
Official docs: https://learn.microsoft.com/en-us/entra/workload-id/workload-identity-federation-create-trust

AWS (STS)

ConfigEnv VarRequired
Role ARNAWF_AUTH_AWS_ROLE_ARN
RegionAWF_AUTH_AWS_REGION
Session NameAWF_AUTH_AWS_ROLE_SESSION_NAME❌ (default: awf-oidc-session)
AudienceAWF_AUTH_OIDC_AUDIENCE❌ (default: sts.amazonaws.com)

Token exchange: GET https://sts.<region>.amazonaws.com/?Action=AssumeRoleWithWebIdentity
Result: Temporary credentials (AccessKeyId, SecretAccessKey, SessionToken), cached and refreshed by AwsOidcTokenProvider

Request signing: SigV4 with service bedrock-runtime, applied after body transforms and repeated for retries

Implementation: containers/api-proxy/aws-oidc-token-provider.js, containers/api-proxy/aws-sigv4.js

Official docs: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_providers_oidc.html

:::note[Signing boundary and fail-closed behavior] The request layer signs the HTTP method, canonical path and sorted query, final body SHA-256, exact regional Bedrock Runtime host, region, and bedrock-runtime service. It includes the STS session token and re-signs retries. Missing/expired credentials return 503 without opening an upstream connection. To prevent credential disclosure, other target hosts and WebSocket upgrades are rejected. :::

GCP (Workload Identity Federation)

ConfigEnv VarRequired
WIF ProviderAWF_AUTH_GCP_WORKLOAD_IDENTITY_PROVIDER
Service AccountAWF_AUTH_GCP_SERVICE_ACCOUNT❌ (direct federation if omitted)
ScopeAWF_AUTH_GCP_SCOPE❌ (default: https://www.googleapis.com/auth/cloud-platform)
AudienceAWF_AUTH_OIDC_AUDIENCE❌ (default: derived from WIF provider)

Token exchange (2-step):

  1. POST https://sts.googleapis.com/v1/token — exchange GitHub JWT for federated token
  2. POST https://iamcredentials.googleapis.com/.../:generateAccessToken — (optional) exchange for SA-scoped token

Implementation: containers/api-proxy/gcp-oidc-token-provider.js
Official docs: https://cloud.google.com/iam/docs/workload-identity-federation-with-deployment-pipelines

Anthropic (Native WIF)

ConfigEnv VarRequired
Federation Rule IDAWF_AUTH_ANTHROPIC_FEDERATION_RULE_ID
Organization IDAWF_AUTH_ANTHROPIC_ORGANIZATION_ID
Service Account IDAWF_AUTH_ANTHROPIC_SERVICE_ACCOUNT_ID
Workspace IDAWF_AUTH_ANTHROPIC_WORKSPACE_ID
Token URLAWF_AUTH_ANTHROPIC_TOKEN_URL❌ (default: https://api.anthropic.com/v1/oauth/token)
AudienceAWF_AUTH_OIDC_AUDIENCE❌ (default: https://api.anthropic.com)

Token exchange: POST https://api.anthropic.com/v1/oauth/token (RFC 7523 jwt-bearer), with anthropic-beta: oauth-2025-04-20,oidc-federation-2026-04-01

Bearer API requests: anthropic-beta: oauth-2025-04-20 (merged with client and auto-cache beta values)

Implementation: containers/api-proxy/anthropic-oidc-token-provider.js

Official references: Anthropic WIF documentation · Anthropic TypeScript SDK credential constants


GitHub Instance Types

Detection logic in containers/api-proxy/providers/copilot-auth.js:

GITHUB_SERVER_URL → deriveCopilotApiTarget():
  *.ghe.com     → copilot-api.<subdomain>.ghe.com
  github.com    → api.githubcopilot.com
  (other)       → api.enterprise.githubcopilot.com

api.business.githubcopilot.com (Business tier) is never auto-derived from GITHUB_SERVER_URL — it must be set explicitly via COPILOT_API_TARGET.

Auth Header Prefix Rules

TargetCredential TypeAuth Header Format
api.githubcopilot.comGitHub tokenBearer <token>
copilot-api.*.ghe.comGitHub tokenBearer <token>
api.enterprise.githubcopilot.comGitHub tokentoken <value>
api.business.githubcopilot.comGitHub tokentoken <value>
Any targetBYOK keyBearer <key> (always)
Any targetOIDC tokenBearer <token> (always)

The token prefix is used for GitHub OAuth tokens on the enterprise and business Copilot targets, or when GHES is otherwise detected (see copilotTargetRequiresGitHubTokenPrefix() in copilot-auth.js). BYOK and OIDC always use Bearer. As noted above, this is AWF-implementation-specific behavior driven by observed 400 errors from those two targets — not a general GitHub REST API requirement.


Custom Headers & Injection

Protected Headers (cannot be overridden)

  • authorization
  • x-api-key
  • x-goog-api-key
  • proxy-authorization

BYOK Extra Headers (AWF_BYOK_EXTRA_HEADERS)

JSON object of headers injected on BYOK inference requests:

  • Only active when COPILOT_PROVIDER_API_KEY is set
  • NOT injected on /models GET when GitHub OAuth token is available
  • Protected headers are skipped with a console.warn message

BYOK Extra Body Fields (AWF_BYOK_EXTRA_BODY_FIELDS)

JSON object of string fields merged into request body:

  • Only active in BYOK mode
  • Existing body fields are NOT overridden

Session Tracking (AWF_PROVIDER_SESSION_ID)

Adds x-session-id header automatically in BYOK mode unless already present.


Coverage Matrix

EngineAuth ModeInstanceTestedImplementation
OpenAIStatic keyopenai.js
OpenAIAzure BYOKopenai.js
OpenAIAzure OIDCopenai.js, oidc-token-provider.js
OpenAIAWS Bedrock OIDC + SigV4openai.js, aws-oidc-token-provider.js, aws-sigv4.test.js
OpenAIGCP OIDCopenai.js, gcp-oidc-token-provider.js
AnthropicStatic keyanthropic.js
AnthropicWIFanthropic.js, anthropic-oidc-token-provider.js
AnthropicCustom headeranthropic.js
CopilotGitHub tokengithub.comcopilot.js, copilot-auth.js
CopilotGitHub tokenGHECcopilot.js, copilot-auth.js
CopilotGitHub tokenGHEScopilot.js, copilot-auth.js
CopilotGitHub tokenBusiness tiercopilot-adapter-enterprise.test.js
CopilotBYOK keycopilot.js, copilot-byok.js
CopilotAzure BYOKvia OpenAI adapter
CopilotAzure OIDCcopilot-adapter-enterprise.test.js
CopilotAWS Bedrock OIDC + SigV4aws-oidc-token-provider.js, server.auth-matrix.test.js
CopilotGCP OIDCgcp-oidc-token-provider.js, server.auth-matrix.test.js
CopilotGHES + BYOKGHESserver.auth-matrix.test.js
GeminiStatic keygemini.js, google-adapter.js
GeminiGCP WIF❌ not implUse the OpenAI adapter with GCP OIDC pointed at a Vertex endpoint instead (see Google Gemini)
Vertex AIStatic keyvertex.js, google-adapter.js
Vertex AIGCP WIF❌ not implNo OIDC support in vertex.js; see Provider: Google Vertex AI

:::note "Implementation" column lists source files, not line numbers — line references go stale quickly as the code evolves. Use your editor's search to locate the relevant logic within each file. :::