Skip to content

Time out idle connections to the auth code receiver - #971

Open
Yashvardhan Thanvi (Thanatos9404) wants to merge 1 commit into
AzureAD:devfrom
Thanatos9404:fix/authcode-idle-connection
Open

Yashvardhan Thanvi (Thanatos9404) wants to merge 1 commit into
AzureAD:devfrom
Thanatos9404:fix/authcode-idle-connection

Conversation

@Thanatos9404

Copy link
Copy Markdown

Fixes #950

AuthCodeReceiver handles one connection at a time through HTTPServer.handle_request(), and _AuthCodeHandler had no read timeout. A client that connects and never sends a request therefore blocks handle_request() inside _get_auth_response(), and the browser's form_post callback sits in the listen backlog behind it. get_auth_response() then returns None at the overall timeout, or never returns when there is none, which is the default for acquire_token_interactive(). The reporter hit this behind VS Code Remote SSH port forwarding, and Daniel Gil (@DanielGilOrtiz) reports it in a VS Code Dev Container and suggests this fix.

This sets timeout = 10 on _AuthCodeHandler. StreamRequestHandler.setup() applies it to each accepted socket, and BaseHTTPRequestHandler.handle_one_request() already treats a read timeout as a closed connection. So handle_request() returns and the loop accepts the queued callback. The overall timeout of get_auth_response() is unchanged.

A client delivering the auth response sends it right after connecting, so in practice only idle connections hit this. Connections a browser opens speculatively and leaves unused are idle too, and are dropped the same way. The limit applies to each read, so a request that is slow to arrive still gets through as long as no single gap reaches 10 seconds.

Idle connections are still handled one after another, so each one queued ahead of the callback adds up to 10 seconds: one idle connection delays the sign-in by about 10 seconds and two by about 20, instead of blocking it. Serving connections in parallel would avoid that, but _get_auth_response() only checks for the response after handle_request() returns, so that is a bigger change and is left out here. The value is a class attribute rather than a new parameter, so the public API does not change. Happy to make it configurable if you prefer.

Tests

Two new tests in tests/test_authcode.py. Each opens raw sockets to 127.0.0.1 that never send anything, then posts the auth response from a thread one second later.

  • test_idle_connection_should_not_block_auth_response: one idle connection, default timeout. On dev it fails after 30 s because get_auth_response() returns None. With this change it passes in 10 to 11 s.
  • test_several_idle_connections_should_not_block_auth_response: three idle connections, with the handler timeout patched to 1 s to keep the test short. It checks that the callback still arrives (about 4 s). Since it sets the timeout itself, it passes on dev too.

The unit test command from .Pipelines/template-pipeline-stages.yml passes on Linux and Windows (Python 3.12); the two authcode test files also pass on Windows with Python 3.9 and 3.14.

Also checked with a small socket script: two and three idle connections (response after about 21 s and 31 s), no overall timeout, a client that waits 9 s before sending, and a request that stops halfway. Not tried with a real browser or az login.

AuthCodeReceiver serves one connection at a time with
HTTPServer.handle_request(). _AuthCodeHandler had no read timeout, so a
client that connected and never sent a request blocked handle_request()
inside _get_auth_response(). The browser's form_post callback then
waited in the listen backlog until the overall timeout, or forever when
there was none. This was seen with az login behind VS Code port
forwarding (Remote SSH and Dev Containers).

Give _AuthCodeHandler a timeout of 10 seconds. StreamRequestHandler
applies it to the accepted socket, and handle_one_request() closes the
connection when a read times out, so handle_request() returns and the
loop accepts the next connection. A client delivering the auth response
sends it right after connecting, so only idle connections are affected.
Each idle connection queued ahead of the callback now delays it by up to
10 seconds instead of blocking it.

Fixes AzureAD#950
Copilot AI balanced review requested due to automatic review settings October 15, 2026 09:26

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] Interactive auth callback hangs forever when an idle connection reaches AuthCodeReceiver first

3 participants