Omit Authorization header when api_key is empty - #795
Open
fern-support wants to merge 4 commits into
Open
Conversation
patched_get_headers called _get_token() a second time, after get_headers() had already called it. For the documented callable api_key form this invoked the supplier twice per request, and a supplier whose value changed between the two calls produced the wrong header: returning "real-token" then "" stripped the Authorization header despite a valid token, and the reverse sent "Bearer " while a valid token was available. Both yield a 401. Inspect the header get_headers() already built instead, matching what patched_async_get_headers has been doing. Co-Authored-By: Claude <noreply@anthropic.com>
jasonozuzu-cohere
approved these changes
Aug 17, 2026
jasonozuzu-cohere
marked this pull request as ready for review
August 18, 2026 10:52
andrewbcohere
approved these changes
Aug 18, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR comes from Fern.
Motivation
Some users point the Python SDK at a proxy or a self-hosted deployment that performs its own authentication upstream. In that setup there is no Cohere API key to supply, but the client always sends an
Authorizationheader. Passing an empty key produces a literalAuthorization: Bearerheader, which some proxies reject outright rather than ignore.This makes an empty
api_keymean "don't send the header at all":Changes
Adds
omit_authorization_header_when_api_key_is_empty()tosrc/cohere/overrides.py, wired intorun_overrides(). It patchesBaseClientWrapper.get_headersandAsyncClientWrapper.async_get_headersso that an empty resolvedapi_keyresults in noAuthorizationheader.Both patches work by inspecting the header that
get_headers()has already built, rather than re-resolving the key. That keeps theapi_keysupplier resolved exactly once per request, which matters becauseapi_keyis documented as accepting a callable: a supplier is invoked a single time, and one whose value changes between calls cannot produce a header that disagrees with the token actually used.The patch is idempotent, guarded by an
_omits_empty_authorizationmarker, so repeatedrun_overrides()calls do not stack wrappers.Behaviour is unchanged whenever a key is present: a real key still yields
Authorization: Bearer <key>, andapi_key=Nonestill falls back to theCO_API_KEYenvironment variable.No
.fernignorechange is needed —src/cohere/overrides.pyandtestsare both already listed there, so regeneration will not clobber these files.Testing
Adds
tests/test_optional_auth.py— 5 tests, no network access or API key required:api_keyomits the header forClient,ClientV2,AsyncClientandAsyncClientV2Bearer <key>""omits the headerVerified locally:
test_optional_auth.py,test_overrides.py,test_client_init.py,test_embed_streaming.pyandtest_embed_utils.pypass (22 passed, 1 skipped), andmypyis clean on both changed files. The live-API test modules were not run locally as they require credentials; CI covers those.Note
Medium Risk
Changes how every HTTP request builds auth headers for all client types; behavior for non-empty keys is unchanged but empty-key and callable-supplier paths are security-sensitive.
Overview
Bumps the SDK to 7.0.9 (metadata,
pyproject.toml, and clientUser-Agent/ Fern headers).Empty
api_keyno longer sendsAuthorization. A new override inoverrides.pypatches sync and async header builders soAuthorization: Beareris removed when the resolved key is empty—supporting proxies/self-hosted endpoints that authenticate elsewhere viacohere.Client(api_key=""). Patches inspect the already-built header (not a second token resolution) so callableapi_keysuppliers run once per request. The patch is idempotent via_omits_empty_authorization.Adds
tests/test_optional_auth.pycovering Client/V2 and async clients, callable keys, and single-invocation behavior.Reviewed by Cursor Bugbot for commit f0602c0. Bugbot is set up for automated code reviews on this repo. Configure here.