Description
DeviceCodeFlow.poll_for_token() is asynchronous, but performs token polling with the synchronous requests.post() API.
While the HTTP request is in progress, control is not returned to the event loop. As a result, unrelated asynchronous tasks running on the same loop cannot make progress until the request completes or times out.
I reproduced this behavior using a local HTTP server that delays its token response for approximately one second.
Observed behavior:
Synchronous HTTP duration: ~1.004 seconds
Expected heartbeat opportunities during the request: 20
Heartbeats executed during the request: 0
External service contacted: No
This means a slow token endpoint can block other asynchronous work sharing the event loop for the duration of each polling request.
Affected Version
Confirmed on:
authsome==0.7.2
Python 3.13.14
src/authsome/auth/flows/device_code.py, DeviceCodeFlow.poll_for_token()
The current main branch also contains the same synchronous requests.post() pattern. The reproduction itself was performed against version 0.7.2.
Reproduction
The attached PoC executes the released DeviceCodeFlow.poll_for_token() implementation against a local HTTP server.
The server deliberately waits one second before returning a successful token response. At the same time, an asynchronous heartbeat task is scheduled to run every 50 ms.
Observed result:
synchronous HTTP interval: 1.004s
expected heartbeat opportunities: 20
heartbeats during requests.post: 0
event loop starved: yes
The heartbeat does not execute while requests.post() is blocked and resumes only after the synchronous request returns.
The reproduction uses only a local loopback HTTP server and does not contact any external service.
Expected behavior
Network I/O performed by an asynchronous authentication flow should not block the event loop.
The token request could use an asynchronous HTTP client, or the synchronous request could be moved off the event-loop thread.
Attachment
run.py
oauth_poll.json
Description
DeviceCodeFlow.poll_for_token() is asynchronous, but performs token polling with the synchronous requests.post() API.
While the HTTP request is in progress, control is not returned to the event loop. As a result, unrelated asynchronous tasks running on the same loop cannot make progress until the request completes or times out.
I reproduced this behavior using a local HTTP server that delays its token response for approximately one second.
Observed behavior:
Synchronous HTTP duration: ~1.004 seconds
Expected heartbeat opportunities during the request: 20
Heartbeats executed during the request: 0
External service contacted: No
This means a slow token endpoint can block other asynchronous work sharing the event loop for the duration of each polling request.
Affected Version
Confirmed on:
authsome==0.7.2
Python 3.13.14
src/authsome/auth/flows/device_code.py, DeviceCodeFlow.poll_for_token()
The current main branch also contains the same synchronous requests.post() pattern. The reproduction itself was performed against version 0.7.2.
Reproduction
The attached PoC executes the released DeviceCodeFlow.poll_for_token() implementation against a local HTTP server.
The server deliberately waits one second before returning a successful token response. At the same time, an asynchronous heartbeat task is scheduled to run every 50 ms.
Observed result:
synchronous HTTP interval: 1.004s
expected heartbeat opportunities: 20
heartbeats during requests.post: 0
event loop starved: yes
The heartbeat does not execute while requests.post() is blocked and resumes only after the synchronous request returns.
The reproduction uses only a local loopback HTTP server and does not contact any external service.
Expected behavior
Network I/O performed by an asynchronous authentication flow should not block the event loop.
The token request could use an asynchronous HTTP client, or the synchronous request could be moved off the event-loop thread.
Attachment
run.py
oauth_poll.json