fix: latch xAI OAuth callback result

This commit is contained in:
Fewmanism 2026-05-18 02:06:00 +09:00 committed by Teknium
parent eac198b6d5
commit 0d63661702
2 changed files with 39 additions and 5 deletions

View file

@ -2372,6 +2372,7 @@ def _make_xai_callback_handler(expected_path: str) -> tuple[type[BaseHTTPRequest
"error": None,
"error_description": None,
}
result_lock = threading.Lock()
class _XAICallbackHandler(BaseHTTPRequestHandler):
def _maybe_write_cors_headers(self) -> None:
@ -2398,16 +2399,27 @@ def _make_xai_callback_handler(expected_path: str) -> tuple[type[BaseHTTPRequest
return
params = parse_qs(parsed.query)
result["code"] = params.get("code", [None])[0]
result["state"] = params.get("state", [None])[0]
result["error"] = params.get("error", [None])[0]
result["error_description"] = params.get("error_description", [None])[0]
incoming = {
"code": params.get("code", [None])[0],
"state": params.get("state", [None])[0],
"error": params.get("error", [None])[0],
"error_description": params.get("error_description", [None])[0],
}
# ThreadingHTTPServer allows a fallback/manual callback to complete
# while a browser connection is stuck. Once we have a terminal
# OAuth result (code or error), keep the first one so a later
# concurrent/invalid callback cannot overwrite state before
# validation in _xai_oauth_loopback_login().
if incoming["code"] or incoming["error"]:
with result_lock:
if not (result["code"] or result["error"]):
result.update(incoming)
self.send_response(200)
self._maybe_write_cors_headers()
self.send_header("Content-Type", "text/html; charset=utf-8")
self.end_headers()
if result["error"]:
if incoming["error"]:
body = "<html><body><h1>xAI authorization failed.</h1>You can close this tab.</body></html>"
else:
body = "<html><body><h1>xAI authorization received.</h1>You can close this tab.</body></html>"

View file

@ -304,6 +304,28 @@ def test_xai_callback_server_accepts_fallback_code_while_browser_connection_is_s
thread.join(timeout=1.0)
def test_xai_callback_server_latches_first_terminal_callback_result():
server, thread, result, redirect_uri = _xai_start_callback_server(preferred_port=0)
try:
with urllib.request.urlopen(f"{redirect_uri}?code=first-code&state=state-1", timeout=2) as response:
assert response.status == 200
with urllib.request.urlopen(
f"{redirect_uri}?error=access_denied&error_description=late&state=state-2",
timeout=2,
) as response:
body = response.read().decode("utf-8")
assert response.status == 200
assert "xAI authorization failed" in body
assert result["code"] == "first-code"
assert result["state"] == "state-1"
assert result["error"] is None
assert result["error_description"] is None
finally:
server.shutdown()
server.server_close()
thread.join(timeout=1.0)
# ---------------------------------------------------------------------------
# Token roundtrip + reads
# ---------------------------------------------------------------------------