Skip to main content

max / makenotwork

mt: give the outbound OAuth calls a per-request timeout fetch_userinfo and exchange_refresh_token inherited only the shared client's 15s total (backstopped by the outer 30s TimeoutLayer). Add a tighter 10s per-request timeout so a stalled MNW OAuth endpoint fails the login/refresh fast instead of parking on the request. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Author: Max Johnson <me@maxj.phd> · 2026-07-07 15:08 UTC
Commit: a66a3469d10669a4f0d13e12b5c4fdebf5233e4f
Parent: b473090
1 file changed, +10 insertions, -0 deletions
@@ -96,6 +96,11 @@ const SESSION_REFRESH_TOKEN: &str = "mnw_refresh_token";
96 96 const SESSION_OAUTH_STATE: &str = "oauth_state";
97 97 const SESSION_PKCE_VERIFIER: &str = "pkce_verifier";
98 98
99 + /// Per-request timeout for the outbound OAuth calls (userinfo, token refresh).
100 + /// Tighter than the shared client's 15s total and the outer 30s TimeoutLayer, so
101 + /// a stalled MNW OAuth endpoint fails the login/refresh fast instead of parking.
102 + const OAUTH_REQUEST_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(10);
103 +
99 104 impl SessionUser {
100 105 async fn from_session(session: &Session) -> Option<Self> {
101 106 let user_id: uuid::Uuid = match session.get(SESSION_USER_ID).await {
@@ -282,6 +287,10 @@ async fn fetch_userinfo(
282 287 let res = http
283 288 .get(&url)
284 289 .bearer_auth(access_token)
290 + // Per-request timeout, tighter than the client's 15s total: an OAuth call
291 + // sits in the login/refresh path and should give up well before the outer
292 + // 30s request TimeoutLayer would (fuzz-2026-07-06 OAuth per-request timeout).
293 + .timeout(OAUTH_REQUEST_TIMEOUT)
285 294 .send()
286 295 .await
287 296 .map_err(|e| {
@@ -324,6 +333,7 @@ async fn exchange_refresh_token(
324 333 "refresh_token": refresh_token,
325 334 "client_id": state.config.oauth_client_id,
326 335 }))
336 + .timeout(OAUTH_REQUEST_TIMEOUT)
327 337 .send()
328 338 .await
329 339 .map_err(|e| {