fix: pass auth via Request constructor instead of calling HTTPBasicAuth on unprepared Request#10748
Conversation
…th on unprepared Request Previously, `HTTPBasicAuth(username, password)(request)` was called on an unprepared `requests.Request` object, which set the Authorization header directly on `request.headers`. When `session.prepare_request()` subsequently processed this request, the Authorization header could be corrupted during header merging — specifically, Base64-encoded credentials were being truncated (e.g., from 260 to 230 characters), causing 401 errors from registries that validate the full token. The fix passes `auth=HTTPBasicAuth(...)` to the `Request()` constructor instead, so the auth callable is properly applied during `prepare_request()` via `prepare_auth()`. This is the idiomatic `requests` library pattern and ensures credentials are correctly encoded in the final prepared request. This primarily affected users authenticating to Google Artifact Registry with OAuth2 access tokens, where the long token values were susceptible to the header corruption during preparation. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Reviewer's guide (collapsed on small PRs)Reviewer's GuideAdjusts how HTTP basic auth is applied to outgoing requests by passing the auth callable into the requests.Request constructor instead of mutating an unprepared Request, preventing Authorization header corruption during prepare_request(). Sequence diagram for applying HTTPBasicAuth via Request constructorsequenceDiagram
participant Client as ClientCode
participant Auth as Authenticator
participant Req as requests_Request
participant HBA as HTTPBasicAuth
participant Sess as requests_Session
Client->>Auth: request(method, url, headers, kwargs)
Auth->>Auth: credential = get_credentials_for_url(url)
alt username_or_password_present
Auth->>HBA: create HTTPBasicAuth(credential.username, credential.password)
HBA-->>Auth: auth
else no_credentials
Auth-->>Auth: auth = None
end
Auth->>Req: new Request(method, url, headers, auth)
Auth->>Sess: get_session(url)
Sess-->>Auth: session
Auth->>Sess: prepare_request(Request)
Sess-->>Auth: PreparedRequest (Authorization set via prepare_auth)
Auth->>Sess: send(PreparedRequest)
Sess-->>Auth: Response
Auth-->>Client: Response
Class diagram for updated Authenticator.request authentication flowclassDiagram
class Authenticator {
+request(method: str, url: str, raise_for_status: bool, kwargs: Any) requests_Response
+get_credentials_for_url(url: str) Credential
+get_session(url: str) requests_Session
}
class Credential {
+username: Optional~str~
+password: Optional~str~
}
class requests_Request {
+method: str
+url: str
+headers: Optional~dict~
+auth: Optional~HTTPBasicAuth~
}
class HTTPBasicAuth {
+username: str
+password: str
+__call__(request: requests_Request) requests_Request
}
class requests_Session {
+prepare_request(request: requests_Request) PreparedRequest
+send(request: PreparedRequest) requests_Response
}
class PreparedRequest {
+headers: dict
+body: Any
}
Authenticator --> Credential : uses
Authenticator --> requests_Request : constructs
Authenticator --> HTTPBasicAuth : constructs
Authenticator --> requests_Session : uses
requests_Session --> PreparedRequest : prepares
HTTPBasicAuth --> requests_Request : configures_auth_on
PreparedRequest --> requests_Request : prepared_from
File-Level Changes
Possibly linked issues
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
|
@sdispater @abn @radoering Hello, hope you're doing well. Would it be possible to get a review on this PR? I have tested the changes locally and they work. Was facing an issue with Auth w.r.t GCP Artifact Registry, have highlighted the issue as well. Let me know if anything else is needed from my side |
|
@Secrus Are you the correct person to ask for a review for this PR? Having a difficult time identifying who has write access |
|
@Affanmir patience please, we will get to reviewing your PR when we have time. |
Summary
HTTPBasicAuth().__call__()was invoked on an unpreparedrequests.Requestobject, setting theAuthorizationheader directly onrequest.headers. Whensession.prepare_request()subsequently processed this request, the header could be corrupted during header merging — specifically, Base64-encoded credentials were truncated (e.g., from 260 to 230 characters), causing 401 Unauthorized errors.auth=HTTPBasicAuth(...)to theRequest()constructor instead, so the auth callable is properly applied duringprepare_request()viaprepare_auth(). This is the idiomaticrequestslibrary pattern.Reproduction
Related Issues
prepare_request).netrccredentials take precedence overpoetry config http-basic#8443 —.netrccredentials take precedence overpoetry config http-basicTest plan
tests/utils/test_authenticator.pypassSummary by Sourcery
Bug Fixes: