fix: handle proxy authentication via CDP Fetch.authRequired (#1000)

* fix: handle proxy authentication via CDP Fetch.authRequired

Chrome's --proxy-server flag does not support credentials embedded in
the URL. When a proxy requires authentication, Chrome receives a 407
from the proxy but has no way to respond with credentials, resulting
in net::ERR_INVALID_AUTH_CREDENTIALS.

Fix by:
1. Parsing credentials from the proxy URL (already done by parse_proxy)
2. Storing them in DaemonState.proxy_credentials
3. Enabling Fetch.enable with handleAuthRequests: true
4. Responding to Fetch.authRequired events with Fetch.continueWithAuth
5. Passing only the server URL (without credentials) to --proxy-server
6. Forwarding credentials to the daemon via dedicated env vars

Also adds fallback to standard proxy env vars (HTTP_PROXY, HTTPS_PROXY,
ALL_PROXY, NO_PROXY) when AGENT_BROWSER_PROXY is not set.

Fixes #990

* refactor: use typed struct for parse_proxy, fix double Fetch.enable and username-only auth

- Replace serde_json::Value return from parse_proxy with a typed ParsedProxy struct
- Fix double Fetch.enable call when both proxy auth and domain filter are active
  (the second call could overwrite handleAuthRequests from the first)
- Allow username-only proxy auth (some proxies don't require a password)
- Handle empty username/password in parse_proxy as None instead of Some("")
- Use install_domain_filter_fetch in auto_launch for consistency
- Update unit tests to use typed struct fields

---------

Co-authored-by: ctate <366502+ctate@users.noreply.github.com>
This commit is contained in:
Chris Tate
2026-03-24 12:52:39 -05:00
committed by GitHub
co-authored by ctate
parent 23a117c5c2
commit cd1f255129
7 changed files with 266 additions and 78 deletions
+12 -2
View File
@@ -353,10 +353,20 @@ pub fn parse_flags(args: &[String]) -> Flags {
extensions,
profile: env::var("AGENT_BROWSER_PROFILE").ok().or(config.profile),
state: env::var("AGENT_BROWSER_STATE").ok().or(config.state),
proxy: env::var("AGENT_BROWSER_PROXY").ok().or(config.proxy),
proxy: env::var("AGENT_BROWSER_PROXY")
.ok()
.or(config.proxy)
.or_else(|| env::var("HTTP_PROXY").ok())
.or_else(|| env::var("http_proxy").ok())
.or_else(|| env::var("HTTPS_PROXY").ok())
.or_else(|| env::var("https_proxy").ok())
.or_else(|| env::var("ALL_PROXY").ok())
.or_else(|| env::var("all_proxy").ok()),
proxy_bypass: env::var("AGENT_BROWSER_PROXY_BYPASS")
.ok()
.or(config.proxy_bypass),
.or(config.proxy_bypass)
.or_else(|| env::var("NO_PROXY").ok())
.or_else(|| env::var("no_proxy").ok()),
args: env::var("AGENT_BROWSER_ARGS").ok().or(config.args),
user_agent: env::var("AGENT_BROWSER_USER_AGENT")
.ok()