Omit Authorization header when api_key is empty - #795
Draft
fern-support wants to merge 2 commits into
Draft
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>
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.