Skip to content

Add authenticated forward-proxy support to HxClient#82

Open
ewels wants to merge 2 commits into
masterfrom
claude/hxclient-proxy-auth-yojr6z
Open

Add authenticated forward-proxy support to HxClient#82
ewels wants to merge 2 commits into
masterfrom
claude/hxclient-proxy-auth-yojr6z

Conversation

@ewels

@ewels ewels commented Jul 7, 2026

Copy link
Copy Markdown
Member

Context

HxClient is the shared HTTP client for Nextflow (SCM pulls, plugin downloads, registry, Tower) and Wave. Users behind an authenticating corporate proxy currently cannot use it: routing works via ProxySelector.getDefault(), but there is no way to supply proxy credentials. Fixing it at this shared layer means every consumer benefits.

Related to nextflow-io/nextflow#7305.

The Authenticator.setDefault limitation

java.net.http.HttpClient ignores Authenticator.setDefault(...) — proxy credentials only take effect when the authenticator is supplied via HttpClient.Builder.authenticator(...). Verified against a local authenticating proxy: default-authenticator gives 407, builder-authenticator gives 200. This is why the fix must live in the client builder rather than in application bootstrap code.

Changes

  • HxClient.Builder.proxy(ProxySelector) and .proxyAuthenticator(Authenticator) passthroughs, forwarded to the inner HttpClient.Builder.
  • HxProxyConfig (new): resolves HTTPS_PROXY/HTTP_PROXY/ALL_PROXY and NO_PROXY (upper and lower case), falling back to the https.proxyHost/http.proxyHost system properties. URL-decodes embedded user:pass@host:port credentials. Its Authenticator releases credentials only for RequestorType.PROXY with matching host/port — never to origin servers (mirrors Nextflow's ProxyConfig). Its ProxySelector honours NO_PROXY and always bypasses loopback targets, consistent with the JDK default http.nonProxyHosts.
  • Auto-configuration: HxClient.newBuilder() with no explicit proxy resolves the configuration from the environment automatically. An explicitly supplied httpClient(...) is used verbatim; with no proxy configured in the environment, behaviour is unchanged.
  • Token-refresh clients: the internal clients used for JWT token refresh (HxTokenManager) and anonymous Bearer token retrieval inherit the same proxy and authenticator via HxConfig, instead of a bare HttpClient.newHttpClient().
  • Version bumped to 2.4.0 with changelog and README updates.

The disabledSchemes dependency

The JDK strips the Basic scheme from HTTPS CONNECT tunnelling by default (jdk.http.auth.tunneling.disabledSchemes=Basic in $JAVA_HOME/conf/net.properties). Basic proxy authentication for HTTPS traffic therefore also requires running the JVM with -Djdk.http.auth.tunneling.disabledSchemes=. This is documented in the README and javadoc, and set for this module's test JVM in build.gradle.

Tests

./gradlew :lib-httpx:test passes (201 tests). New coverage:

  • Integration tests against a local authenticating proxy (raw-socket MockAuthProxyServer) that returns 407 without Proxy-Authorization and 200 with the correct Basic credentials: HxClient succeeds when credentials are supplied and gets 407 when they are absent.
  • HTTPS CONNECT tunnelling case: asserts the challenge/retry handshake carries the Basic credentials on the CONNECT request (with disabledSchemes cleared for the test JVM).
  • Token-refresh POST routed through the authenticating proxy.
  • Unit tests for environment parsing precedence, credential URL-decoding, NO_PROXY matching, and authenticator scoping (proxy-only, host/port match).

🤖 Generated with Claude Code

https://claude.ai/code/session_01G5qZcbMECP5sixEQqivWXM


Generated by Claude Code

claude added 2 commits July 7, 2026 21:27
java.net.http.HttpClient ignores Authenticator.setDefault(), so proxy
credentials only take effect when supplied via
HttpClient.Builder.authenticator(). This adds first-class proxy support
at the HxClient layer so every consumer benefits:

- Add proxy(ProxySelector) and proxyAuthenticator(Authenticator)
  passthroughs on HxClient.Builder, forwarded to the inner
  HttpClient.Builder
- Add HxProxyConfig helper that resolves HTTPS_PROXY/HTTP_PROXY/
  ALL_PROXY and NO_PROXY (both cases), falling back to the
  https.proxyHost/http.proxyHost system properties, URL-decoding
  embedded user:pass@host:port credentials; its Authenticator releases
  credentials only for RequestorType.PROXY and the matching host/port
- Auto-configure proxy and credentials from the environment when
  HxClient.newBuilder() is used with no explicit proxy; an explicitly
  supplied httpClient(...) is used verbatim
- Make the token-refresh and anonymous Bearer token clients inherit the
  same proxy and authenticator via HxConfig
- Integration tests against a local authenticating proxy covering plain
  HTTP (407 without credentials, 200 with) and the HTTPS CONNECT
  tunnelling case, with jdk.http.auth.tunneling.disabledSchemes cleared
  for the test JVM since the JDK strips Basic from CONNECT by default

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01G5qZcbMECP5sixEQqivWXM
- Extract the proxy/authenticator application into a shared
  HxConfig.applyProxySettings() helper instead of repeating the same
  null-guarded block at the three HttpClient.Builder construction sites
- Precompute the Proxy lists in HxProxyConfig.toProxySelector() so
  select() no longer allocates on every request
- Drop the unused HxProxyConfig.getNoProxyHosts() accessor
- Deduplicate the Authenticator.setDefault/disabledSchemes javadoc
  caveats, keeping the canonical text on HxProxyConfig

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01G5qZcbMECP5sixEQqivWXM
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants