Originally published on proxymint.
OkHttp proxy setup in Kotlin and Java for OkHttp 4.12 and 5.x: proxyAuthenticator done right, SOCKS5 logins, the system proxy, rotation and the 407 traps.
TL;DR
- A Proxy plus a proxyAuthenticator is the whole setup. Pass Proxy(Proxy.Type.HTTP, InetSocketAddress(HOST, PORT)) to OkHttpClient.Builder.proxy() and return a request with a Proxy-Authorization header built by Credentials.basic from proxyAuthenticator. HTTPS targets then go through a CONNECT tunnel.
- Interceptors never reach the CONNECT. A Proxy-Authorization header added in an interceptor works for http:// URLs and never for https:// URLs, which explains "Failed to authenticate with proxy" with the right password.
- Guard the authenticator. Return null when the request already carries Proxy-Authorization. Without that check a wrong password costs 21 tunnel attempts, or an endless loop against a proxy that keeps the connection open.
- SOCKS5 logins come from java.net.Authenticator. OkHttp hands SOCKS to the JDK, which asks the JVM-wide default Authenticator; proxyAuthenticator is never called. OkHttp sends the hostname to the SOCKS proxy, so DNS resolves there.
Key takeaways
- Copy the guarded authenticator, not the one-liner. Check response.request.header("Proxy-Authorization") first, so a refused login ends in one IOException instead of a retry storm against the proxy.
- Scope the SOCKS5 Authenticator. Answer only when requestingProtocol is SOCKS5 and the host and port match the proxy, because Authenticator.setDefault applies to the whole JVM.
- Turn off connection reuse only where a fresh exit matters. A client with ConnectionPool(0, 1, TimeUnit.SECONDS) opens a new tunnel per call; the default pool keeps one tunnel and one exit for up to 5 idle minutes.
- Use newBuilder() for per-proxy clients. Derived clients share the pool and dispatcher, and pooled connections never cross proxies, so a round robin over a list stays cheap.
- Use Maven artifact okhttp-jvm for OkHttp 5. The plain okhttp artifact is empty in Maven builds; Gradle resolves it on its own.
Read the full guide on proxymint, with the commands, tables and sources.
Top comments (0)