feat(oauth): retry adjacent ports when OAuth callback port is busy#306
Open
Destynova2 wants to merge 1 commit intomainfrom
Open
feat(oauth): retry adjacent ports when OAuth callback port is busy#306Destynova2 wants to merge 1 commit intomainfrom
Destynova2 wants to merge 1 commit intomainfrom
Conversation
The OAuth callback listener (src/server/lifecycle.rs) used to fail outright when its configured port (1455 by default, see oauth.rs:161 for OpenAI Codex and oauth.rs:191 for Gemini) was already in use by another local process, making the OAuth flow unrecoverable for users with port collisions. The callback now binds the configured port first and falls back to up to 9 adjacent ports (10 total attempts). The actually-bound port is stored in AppState::actual_oauth_callback_port; oauth_authorize / oauth_exchange / oauth_refresh_token rebuild the localhost redirect_uri with this port via the new OAuthConfig::with_callback_port helper so the auth URL stays in sync with the live listener. Anthropic's remote redirect_uri is left alone. If every port in the range is busy, the error log now reads: "Failed to bind OAuth callback server on 127.0.0.1 in port range 1455..=1464". Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
src/server/lifecycle.rspreviously did a singleTcpListener::bindon the configuredoauth_callback_port(default 1455). When that port was busy, the OAuth flow simply broke — the user had to manually free the port to recover.crate::shared::net::bind_with_port_retryhelper. The actually-bound port is stored inAppState::actual_oauth_callback_portso the OAuth handlers can build aredirect_urithat matches the live listener.OAuthConfig::with_callback_portrewrites the localhost callback URL in the configs atsrc/auth/oauth.rs:161(OpenAI Codex) andsrc/auth/oauth.rs:191(Gemini). Anthropic's remoteconsole.anthropic.comredirect is untouched.info!when the configured port worked.warn!(OAuth callback port {} busy; bound on 127.0.0.1:{} instead) on fallback.error!(Failed to bind OAuth callback server on 127.0.0.1 in port range 1455..=1464) when every attempt failed.src/shared/net.rsfor the retry helper, 3 insrc/auth/oauth.rsforwith_callback_port) cover: free base port, falling back to next port, zero-attempts rejection, exhausted range error, localhost rewrite for OpenAI Codex, localhost rewrite for Gemini, and remote redirect untouched for Anthropic.Test plan
cargo fmt --checkcargo clippy --tests --all-targets -- -D warningscargo nextest run --lib auth::oauth shared::net— 13/13 passcargo nextest run --libclean for everything except 4 pre-existing failures already broken onmain(missingpresets/{medium,local,cheap,fast}.tomlreferenced bysrc/preset/mod.rs); those failures are unrelated to this PR.🤖 Generated with Claude Code