A user behind an enterprise gateway that authenticates on Authorization: Bearer <jwt> cannot connect a provider. customHeaders excludes five header names (packages/ai-provider-bridge/src/custom-headers.ts:5-11), two of which carry credentials: authorization and x-api-key. Setting either produces no error and no header on the wire.
The exclusion exists because the direct-SDK request path overwrites its own headers with a user's on collision: sending a user header and the built-in credential together would put two conflicting credentials on one request (memory-bank/architecture.md:239). Lifting the exclusion for these two names means resolving that conflict instead of leaving it unhandled.
Proposal
Accept authorization and x-api-key in customHeaders, and suppress the built-in credential for that request when the user supplies either, so exactly one credential goes out.
Leave accept, anthropic-version, and content-type excluded — they carry no credential and overriding them breaks protocol negotiation.
Design constraints
The exclusion currently lives in the bridge at request time, so a caller that calls fetch directly bypasses it. Move the name exclusion into ai-config, applied at catalog resolution, so every consumer of a resolved connection gets the same set, and delete the bridge's copy. Keep collision de-duplication per-request, since it needs the request's actual base headers, which don't exist at resolution time. Log when a header is excluded so a surface can tell the user it's never sent rather than silently omitting it.
The editing modal reads the raw user-layer entry byte-for-byte, so an excluded header stays visible and editable in providers.json without reaching a request.
For direct-SDK providers, the SDK applies its own headers after the ones it's given, so suppression has to happen when the client is constructed, not when headers merge. The OpenAI-compatible path merges headers itself and can suppress at merge time.
Gemini authenticates with its own API-key header name, which doesn't collide with authorization, so validation would send a configured authorization header while chat drops it unless filtering happens at resolution rather than only at the direct-SDK/OpenAI-compatible merge points.
Open questions
Enforced settings merge per key rather than replacing the map (packages/ai-config/src/enforce.ts:64-85), so user-supplied keys always survive and an empty enforced map is a no-op. Once a user can override the credential, a Workbench admin has no way to stop them overriding the one their deployment issues. This needs a decision before the change ships.
Whether to warn or fail when a user sets both an auth header and an API key for the same provider, rather than silently preferring one.
Related
A user behind an enterprise gateway that authenticates on
Authorization: Bearer <jwt>cannot connect a provider.customHeadersexcludes five header names (packages/ai-provider-bridge/src/custom-headers.ts:5-11), two of which carry credentials:authorizationandx-api-key. Setting either produces no error and no header on the wire.The exclusion exists because the direct-SDK request path overwrites its own headers with a user's on collision: sending a user header and the built-in credential together would put two conflicting credentials on one request (
memory-bank/architecture.md:239). Lifting the exclusion for these two names means resolving that conflict instead of leaving it unhandled.Proposal
Accept
authorizationandx-api-keyincustomHeaders, and suppress the built-in credential for that request when the user supplies either, so exactly one credential goes out.Leave
accept,anthropic-version, andcontent-typeexcluded — they carry no credential and overriding them breaks protocol negotiation.Design constraints
The exclusion currently lives in the bridge at request time, so a caller that calls
fetchdirectly bypasses it. Move the name exclusion intoai-config, applied at catalog resolution, so every consumer of a resolved connection gets the same set, and delete the bridge's copy. Keep collision de-duplication per-request, since it needs the request's actual base headers, which don't exist at resolution time. Log when a header is excluded so a surface can tell the user it's never sent rather than silently omitting it.The editing modal reads the raw user-layer entry byte-for-byte, so an excluded header stays visible and editable in
providers.jsonwithout reaching a request.For direct-SDK providers, the SDK applies its own headers after the ones it's given, so suppression has to happen when the client is constructed, not when headers merge. The OpenAI-compatible path merges headers itself and can suppress at merge time.
Gemini authenticates with its own API-key header name, which doesn't collide with
authorization, so validation would send a configuredauthorizationheader while chat drops it unless filtering happens at resolution rather than only at the direct-SDK/OpenAI-compatible merge points.Open questions
Enforced settings merge per key rather than replacing the map (
packages/ai-config/src/enforce.ts:64-85), so user-supplied keys always survive and an empty enforced map is a no-op. Once a user can override the credential, a Workbench admin has no way to stop them overriding the one their deployment issues. This needs a decision before the change ships.Whether to warn or fail when a user sets both an auth header and an API key for the same provider, rather than silently preferring one.
Related
customHeaderspositron#15248 sends configured headers on validation requests without changing which names are accepted; this issue covers the two names that fix leaves out.