Skip to content

How to Use Proxies With OkHttp (Java, Kotlin, Android)

How OkHttp 5.5 uses a proxy, from its source: proxy() over the selector, CONNECT and the proxyAuthenticator, SOCKS through Java, timeouts and errors.

HProxy TeamAugust 23, 2026Updated October 13, 20268 min read

How to Use Proxies With OkHttp (Java, Kotlin, Android)

OkHttp takes a proxy in one of two ways. You set it on the client with proxy(), or OkHttp asks a ProxySelector each time it opens a new connection. For an https:// site it opens a CONNECT tunnel through an HTTP proxy and answers the proxy's login challenges through a proxyAuthenticator. A SOCKS proxy goes to Java's own socket.

This guide follows OkHttp's source, documentation and change log up to version 5.5.0 of August 16, 2026, read on October 13, 2026, together with Oracle's Java networking properties. None of the code was run for this page. One note for anyone looking up the source: github.com/square/okhttp now redirects to github.com/lysine-dev/okhttp.

Setting a proxy on the client

OkHttp's builder takes a java.net.Proxy, Java's own class, with the proxy's type and address.

OkHttpClient client = new OkHttpClient.Builder()
    .proxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress("203.0.113.7", 8080)))
    .build();

The same in Kotlin:

val client = OkHttpClient.Builder()
    .proxy(Proxy(Proxy.Type.HTTP, InetSocketAddress("203.0.113.7", 8080)))
    .build()

OkHttp's own documentation describes proxy() this way: it "Sets the HTTP proxy that will be used by connections created by this client." A selector is the fallback, "which is only honored when this proxy is null". And Proxy.NO_PROXY switches proxies off: "To disable proxy use completely, call" proxy(Proxy.NO_PROXY).

For calls that need another proxy, derive a second client with newBuilder(). In OkHttp's words, that client "shares the same connection pool, thread pools, and configuration", so a client per proxy costs little. For Java's own HttpClient and HttpURLConnection, see our Java proxy guide.

Printed on our own machine on October 13, 2026, from OkHttp's source and documentation, saved that day; no request was made while printing and no OkHttp code was run.

When you set no proxy: the ProxySelector

With proxy() left unset, OkHttp asks a ProxySelector, and without one of yours it uses Java's system-wide default. Its documentation adds that a selector "may return multiple proxies; in that case they will be tried in sequence until" one connects.

Java's default selector reads a few properties. Oracle lists http.proxyHost, https.proxyHost and socksProxyHost, each with no default. It takes the operating system's own proxy settings only with java.net.useSystemProxies, which defaults to false, and "Note that this property is checked only once at startup." On Android, the system settings carry their own warning about a Wi-Fi proxy: "The HTTP proxy is used by the browser but may not be used by the other apps." Set the proxy on the client when it has to apply.

Two changes in OkHttp 5 concern the selector. Version 5.0.0-alpha.15 of May 2025 began calling ProxySelector.connectFailed() when a connection's first TCP handshake fails. And version 5.5.0 notes: "Fix: Fall back to no proxy when the system proxy selector throws." Before that, the call crashed.

How OkHttp reaches an https:// site through an HTTP proxy

How OkHttp reaches an https:// site through an HTTP proxy
  1. Pick the proxy

    proxy(), else the selector, else Java's default

  2. Ask the authenticator

    a stand-in 407 named OkHttp-Preemptive

  3. Send CONNECT

    only the host, none of your headers

  4. Proxy answers 407

    proxyAuthenticator again; at most 21 tries

  5. Proxy answers 200

    TLS to the site runs inside the tunnel

Source: OkHttp source: OkHttpClient.kt, Authenticator.kt and ConnectPlan.kt, read October 13, 2026 · hproxy.comProxy.

OkHttp's connection code states the plan in one line: "To make an HTTPS connection over an HTTP proxy, send an unencrypted CONNECT request to create" the tunnel. OkHttp writes that request itself, with the site's host and port. Its documentation explains what the CONNECT leaves out: it "doesn't include the motivating request's HTTP headers or even its full URL". It also skips your interceptors and event listeners.

That is why a Proxy-Authorization header added to your own request does nothing for an https:// site. The proxy only ever sees the CONNECT, and the login has to come from the authenticator.

Logging in to an HTTP proxy

The proxyAuthenticator answers the proxy's challenges. OkHttp's documentation names its job: it "Sets the authenticator used to respond to challenges from proxy servers." This one covers both cases below.

OkHttpClient client = new OkHttpClient.Builder()
    .proxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress("203.0.113.7", 8080)))
    .proxyAuthenticator((route, response) -> {
        if (response.request().header("Proxy-Authorization") != null) {
            return null; // these credentials already failed
        }
        String credential = Credentials.basic("myuser", "mypass");
        return response.request().newBuilder()
            .header("Proxy-Authorization", credential)
            .build();
    })
    .build();

OkHttp calls it twice over. "Prior to sending any CONNECT request OkHttp always calls the proxy authenticator so that it may" prepare a login in advance. For that call it passes a stand-in 407 response with the challenge OkHttp-Preemptive, so the code above sends the credentials with the first CONNECT. Then, "When reactive authentication is requested by a proxy server, the response code is 407", and the authenticator is asked again. RFC 9110 defines the 407 as the proxy telling the client to "authenticate itself in order to use a proxy for this request".

The check at the top keeps a wrong password from looping. OkHttp's own example does the same with "return null; // Give up, we've already failed to authenticate." When the authenticator returns null after a real 407, OkHttp throws "Failed to authenticate with proxy". Any other answer than 200 or 407 throws "Unexpected response code for CONNECT" with the code. And the tunnel code allows MAX_TUNNEL_ATTEMPTS = 21 before it gives up with "Too many tunnel connections attempted". Our guide to 407 Proxy Authentication Required covers the login side, and the page on ERR_TUNNEL_CONNECTION_FAILED reads the proxy's other answers.

SOCKS proxies

For SOCKS, change the type. The login then goes through Java itself.

OkHttpClient client = new OkHttpClient.Builder()
    .proxy(new Proxy(Proxy.Type.SOCKS, new InetSocketAddress("203.0.113.7", 1080)))
    .build();

// A SOCKS5 login, for the whole JVM:
java.net.Authenticator.setDefault(new java.net.Authenticator() {
    @Override protected java.net.PasswordAuthentication getPasswordAuthentication() {
        return new java.net.PasswordAuthentication("myuser", "mypass".toCharArray());
    }
});

Two lines in OkHttp's source explain the difference. For a SOCKS route it builds the target with InetSocketAddress.createUnresolved(socketHost, socketPort). The hostname reaches the proxy unresolved, so the proxy looks it up. And it opens the connection with JavaNetSocket(route.proxy), a Java socket that speaks SOCKS itself, where HTTP and direct routes use the client's socket factory.

So the SOCKS login follows Java's rules. Oracle's properties set socksProxyVersion to 5 by default, and java.net.socks.username is the "Username to use if the SOCKSv5 server asks for authentication" when no java.net.Authenticator is set. OkHttp's proxyAuthenticator answers the HTTP proxy's 407 challenges.

Who talks to the proxy, by Proxy.Type

TypeConnectsLogin
HTTPOkHttpIts callback
SOCKSJava's socketJava settings
DIRECTOkHttpNone needed

OkHttp source: ConnectPlan.kt and RouteSelector.kt; Oracle, Java Networking Properties; read October 13, 2026

Spreading calls over several proxies

OkHttp chooses a proxy when it opens a connection and then reuses that connection. Its connections document puts the order plainly. First OkHttp looks in the connection pool, and only "If it doesn't find a connection in the pool" does it plan a route: "It then selects a TLS version and proxy server if necessary." After a call, "the connection will be returned to the pool so it can be reused for a future request."

So a ProxySelector that returns a different proxy each time changes only the connections opened after it. Two set-ups behave predictably. A rotating gateway keeps one proxy address in OkHttp while the outgoing address changes behind it. Or build one client per proxy with newBuilder() and pick the client per call. Use addresses you are allowed to use, and keep each site's own rules: its terms and its robots.txt apply whatever the address.

Timeouts

OkHttp's defaults are in its source: connect, read and write each default to 10 seconds, and the call timeout is "The default value is 0 which imposes no timeout." The CONNECT exchange uses the read and write timeouts, so a proxy that accepts the connection and then stalls hits the read timeout.

OkHttpClient client = new OkHttpClient.Builder()
    .proxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress("203.0.113.7", 8080)))
    .connectTimeout(java.time.Duration.ofSeconds(5))
    .readTimeout(java.time.Duration.ofSeconds(20))
    .callTimeout(java.time.Duration.ofSeconds(30))
    .build();

A call timeout bounds the whole call, retries and redirects included, which suits unattended jobs.

Check the exit

Send one call through the proxied client to a page that shows your address, and compare it with the address you see without the proxy. Our proxy checker tests a proxy from your own connection before you build a client around it, and our free proxy API returns recently checked addresses with no key, enough for a first test.

  • ZenRows writes that "OkHttp provides a Proxy class that offers a way to represent a proxy server." The class is java.net.Proxy, Java's own, which OkHttp's builder takes. The same page sells the proxy as a way to "scrape undetected".
  • Decodo says "proxyAuthenticator adds the credentials automatically and retries the request." That describes the reactive path. OkHttp also asks the authenticator before every CONNECT, with the OkHttp-Preemptive challenge.
  • Scrapfly's guide to OkHttp shows no proxy() or proxyAuthenticator setup and sends readers to "Anti-bot bypass".
  • ScrapingBee's Kotlin guide shows no OkHttp proxy setup and points to "A guide to Web Scraping without getting blocked".
  • MarsProxies sells rotation for "rotate identities, detect soft blocks" and "detection evasion". A proxy changes the address a request comes from, and each site's rules stay the same.

Where HProxy fits

Our residential proxies give a fresh IP per request from $0.44 per GB, behind one gateway address, which suits the rotating set-up above. Premium holds one address for up to 24 hours from $1.00 per GB, and it takes an IP whitelist, which spares the login. Our datacenter IPv4 proxies, from $1.58 per IP, speak HTTP, HTTPS and SOCKS5. With OkHttp, set our HTTP endpoint with proxy() and the login in a proxyAuthenticator; for SOCKS5, the login goes through Java's settings as shown above.

What we could not find out

  • How Android's own selector treats a Wi-Fi proxy for OkHttp. We read Android's settings text only.
  • Whether some SOCKS proxies refuse an unresolved hostname. OkHttp sends one; we ran no code and used no proxy.
  • Why OkHttp's repository moved. The project's pages we read give no reason.

Sources

Read on October 13, 2026.

Frequently asked questions

How do I set a proxy in OkHttp?

Pass a java.net.Proxy to the client builder: new OkHttpClient.Builder().proxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress(host, port))).build(). Every connection that client creates uses it, and it takes precedence over any ProxySelector. For a SOCKS proxy use Proxy.Type.SOCKS. To ignore every proxy, including the system's, pass Proxy.NO_PROXY.

How do I authenticate an OkHttp proxy?

For an HTTP proxy, set a proxyAuthenticator on the builder that returns the request with a Proxy-Authorization header, built with Credentials.basic(user, pass). OkHttp calls it before every CONNECT, with a challenge named OkHttp-Preemptive, and again when the proxy answers 407. For https:// sites a header on your own request never reaches the proxy, because the CONNECT request carries only the target host. A SOCKS5 login goes through Java's own settings instead.

How do I rotate proxies in OkHttp?

OkHttp picks a proxy when it opens a new connection, and it reuses pooled connections. So either point one client at a rotating gateway, where the address changes behind one proxy, or build one client per proxy with newBuilder(), which shares the connection pool and thread pools. A ProxySelector that returns a different proxy each time changes only new connections. Use addresses you are allowed to use; each site's own rules still apply.

Does OkHttp support SOCKS5 proxies?

Yes, with Proxy.Type.SOCKS. OkHttp hands the SOCKS proxy the target hostname unresolved, so the proxy resolves it, and it opens Java's own proxied socket. Java speaks SOCKS version 5 by default and takes a username and password from a java.net.Authenticator or the java.net.socks.username and java.net.socks.password properties. OkHttp's proxyAuthenticator answers the HTTP proxy's 407 challenges.

Why is my OkHttp proxy being ignored?

Look at the client you send with. A proxy set with proxy() applies to the connections that client creates. A client with no proxy falls back to the JVM's default selector, which uses http.proxyHost, https.proxyHost or socksProxyHost when they are set, and the system's own settings only with java.net.useSystemProxies. On Android, the Wi-Fi proxy may not reach apps other than the browser, so set the proxy on the client.

What does Failed to authenticate with proxy mean in OkHttp?

OkHttp throws it when the proxy answers its CONNECT with 407 and your proxyAuthenticator returns null, which it should do once the credentials it sent have failed. Check the username and password. Any answer other than 200 or 407 ends in Unexpected response code for CONNECT with the code, and more than 21 attempts at one tunnel end in Too many tunnel connections attempted.

Does OkHttp use the system proxy?

Only through Java's default ProxySelector, which OkHttp uses when you set no proxy. On a desktop JVM that selector reads http.proxyHost, https.proxyHost and socksProxyHost, and reads the operating system's settings only when java.net.useSystemProxies is true, a property checked once at startup. OkHttp 5.5.0 falls back to no proxy if that selector throws.

Get proxies that are alive right now

Our free proxy list re-checks every exit every few minutes across 100+ countries, with a live last-checked time, so you copy IPs that worked moments ago, not a stale text dump. When the location has to survive a real check, the paid network holds up.

129M+ proxy checks run · 100+ countries · HTTP / HTTPS / SOCKS · re-checked every few minutes · no signup

HProxy.

Honest guides and comparisons on proxies, scraping and staying unblocked, from the team that runs the network.

RSS feed