Skip to content

Bug: the App installation token request ignores the client timeout #331

Closed

Description

@moshe-unitrail

Describe the bug

GitHub(..., timeout=...) is not applied to the installation-token request that AppInstallationAuthStrategy's auth flow sends. That request goes out with no timeout extension, so httpcore reads no timeout and the request can wait forever. Only the API request that follows gets the configured timeout.

The cause appears to be that the auth flow yields a fresh httpx.Request (auth/app.py, the token exchange in sync_auth_flow / async_auth_flow). httpx sets the timeout extension only on the request passed to send(), not on requests an Auth flow yields, so httpcore sees None.

Reproduction

githubkit 0.15.1 (the token-exchange code is unchanged in 0.16.1), httpx 0.28.1, Python 3.14:

import httpx
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric import rsa
from githubkit import AppInstallationAuthStrategy, GitHub

key = rsa.generate_private_key(public_exponent=65537, key_size=2048).private_bytes(
    serialization.Encoding.PEM, serialization.PrivateFormat.PKCS8, serialization.NoEncryption()
).decode()
seen = []

def handler(request: httpx.Request) -> httpx.Response:
    seen.append((request.method, request.url.path, request.extensions.get("timeout")))
    if request.url.path.endswith("access_tokens"):
        return httpx.Response(201, json={"token": "t", "expires_at": "2099-01-01T00:00:00Z", "permissions": {}, "repository_selection": "all"})
    return httpx.Response(404)

gh = GitHub(AppInstallationAuthStrategy(1, key, 2), timeout=5, transport=httpx.MockTransport(handler))
try:
    gh.rest.users.get_by_username("x")
except Exception:
    pass
print(*seen, sep="\n")

Output:

('POST', '/app/installations/2/access_tokens', None)
('GET', '/users/x', {'connect': 5, 'read': 5, 'write': 5, 'pool': 5})

Expected

The token request carries the same timeout as the client. Otherwise the first call on every App-installation client, and each token refresh, can hang indefinitely.

Possible fix

Set request.extensions["timeout"] from the client's configured timeout on each request the auth flow yields, in both the sync and async flows.

Activity

  1. yanyongyu commented on Oct 14, 2026

    @yanyongyu
    Owner

    Maybe we should use client.build_request to construct the exchange request. httpx handles the timeout in the extensions. https://github.com/encode/httpx/blob/b5addb64f0161ff6bfe94c124ef76f6a1fba5254/httpx/_client.py#L340-L389

    Also we can copy the options from the incoming request object.

  2. linked a pull request that will close this issueFix: Apply client timeout to Auth requests #332on Oct 25, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

bugSomething isn't working

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions