microsoft/semantic-kernel · error · Exception

Timeout waiting for OAuth callback

Error message

Timeout waiting for OAuth callback

What it means

Raised by CallbackServer.wait_for_callback when the 300-second (default) timeout elapses without receiving an authorization_code and without an error. The local callback server polls callback_data every 0.1s; if no callback ever arrives, it gives up.

Source

Thrown at python/samples/demos/mcp_with_oauth/agent/main.py:155

    def stop(self):
        """Stop the callback server."""
        if self.server:
            self.server.shutdown()
            self.server.server_close()
        if self.thread:
            self.thread.join(timeout=1)

    def wait_for_callback(self, timeout=300):
        """Wait for OAuth callback with timeout."""
        start_time = time.time()
        while time.time() - start_time < timeout:
            if self.callback_data["authorization_code"]:
                return self.callback_data["authorization_code"]
            if self.callback_data["error"]:
                raise Exception(f"OAuth error: {self.callback_data['error']}")
            time.sleep(0.1)
        raise Exception("Timeout waiting for OAuth callback")

    def get_state(self):
        """Get the received state parameter."""
        return self.callback_data["state"]


async def main():
    # 1. Create the agent
    callback_server = CallbackServer(port=3030)
    callback_server.start()

    async def callback_handler() -> tuple[str, str | None]:
        """Wait for OAuth callback and return auth code and state."""
        print("⏳ Waiting for authorization callback...")
        try:
            auth_code = callback_server.wait_for_callback(timeout=300)
            return auth_code, callback_server.get_state()
        finally:

View on GitHub (pinned to c028a0c7dc)

Solutions

  1. Verify the OAuth redirect_uri in the provider app registration points to the callback server's host:port (e.g. http://localhost:3030/callback).
  2. Confirm port 3030 is free and reachable locally; change the port and redirect_uri together if needed.
  3. Increase the timeout argument if the user legitimately needs more time.
  4. Ensure the user actually completes the consent flow in the browser.

Example fix

// before
code = callback_server.wait_for_callback()  # default 300s

// after
code = callback_server.wait_for_callback(timeout=600)  # or fix redirect_uri registration
Defensive patterns

Strategy: retry

Validate before calling

import socket
def port_open(host='127.0.0.1', port=3030) -> bool:
    with socket.socket() as s:
        return s.connect_ex((host, port)) == 0

Try / catch

try:
    code = callback_server.wait_for_callback(timeout=300)
except Exception as e:
    if 'Timeout' in str(e):
        # verify redirect_uri registration / port, then retry once
        raise
    raise

Prevention

When it happens

Trigger: The OAuth redirect never reaches the local callback server (port 3030); the user closed the browser before completing consent; the redirect_uri is misrouted; a firewall blocks the inbound callback; the callback server failed to bind.

Common situations: Wrong redirect_uri registered so the provider redirects elsewhere; the local port (3030) is already in use or firewalled; the user abandons the flow; network/VPN blocking localhost callbacks.

Understand the failure class

Related errors


AI-assisted analysis of microsoft/semantic-kernel@c028a0c7dc (2026-08-13). Data as JSON: /api/errors/14aa04e9c2f8bd6d. Report an issue: GitHub.