Java HttpClient with AeonProxy proxies

Point java.net.http.HttpClient at port 7000 with a ProxySelector, allow Basic auth for HTTPS tunnels, and log in with an Authenticator or a header.

Protocols
HTTP proxy in HttpClient; SOCKS5 only in HttpURLConnection
Authentication
Login and password through an Authenticator or a Proxy-Authorization header
Rotation
A new IP per connection (a client pools its connections); a -sid- key keeps one IP for up to 60 minutes
Works with
Residential and mobile proxies

Before you start

  • Java 11 or newer; the sessions example needs Java 21, where HttpClient can be closed. Run a file with java ProxyExample.java, no build step.
  • Your proxy login and password from the Residential or Mobile page of the dashboard, and traffic on that product; without traffic every request gets 402.
Connection details
Host
gate.aeonproxy.com
Port (HTTP / HTTPS)
7000
Port (SOCKS5)
7001
Login
your proxy login, with targeting keys if you need them: LOGIN-cc-us-sid-abc123
Password
your proxy password

Copy the login and password from the Residential or Mobile page of the dashboard; the generator there also writes ready lines. Key syntax: targeting and sessions.

Allow Basic auth for HTTPS tunnels

The JDK's conf/net.properties sets jdk.http.auth.tunneling.disabledSchemes=Basic, so Java sends no login on the CONNECT request that opens an HTTPS tunnel, and every HTTPS request through the gateway ends with status 407, even with the right password. Clear the list on the command line:

java -Djdk.http.auth.tunneling.disabledSchemes= ProxyExample.java

or with System.setProperty("jdk.http.auth.tunneling.disabledSchemes", "") before the first client is built: Java reads the setting only once. http:// sites are not affected.

HttpClient with a ProxySelector and an Authenticator

ProxySelector.of points the client at port 7000. Its first CONNECT goes out without a login; after the gateway's 407 the client asks the Authenticator, repeats the request with the login, and sends the login up front on its later connections. Answer only for requestor type PROXY, so websites never get the password.

import java.net.Authenticator;
import java.net.InetSocketAddress;
import java.net.PasswordAuthentication;
import java.net.ProxySelector;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;

public class ProxyExample {
    public static void main(String[] args) throws Exception {
        // Basic auth for HTTPS tunnels is off by default: allow it before the first client is built
        System.setProperty("jdk.http.auth.tunneling.disabledSchemes", "");

        HttpClient client = HttpClient.newBuilder()
            .proxy(ProxySelector.of(new InetSocketAddress("gate.aeonproxy.com", 7000)))
            .authenticator(new Authenticator() {
                @Override
                protected PasswordAuthentication getPasswordAuthentication() {
                    if (getRequestorType() != RequestorType.PROXY) return null; // never send it to websites
                    return new PasswordAuthentication("LOGIN-cc-us", "PASSWORD".toCharArray());
                }
            })
            .connectTimeout(Duration.ofSeconds(30))
            .build();

        HttpRequest req = HttpRequest.newBuilder(URI.create("https://api.ipify.org"))
            .timeout(Duration.ofSeconds(30)).build();
        HttpResponse<String> res = client.send(req, HttpResponse.BodyHandlers.ofString());
        System.out.println(res.statusCode() + " " + res.body());
    }
}

Rotating or sticky

A client pools its connections, so its requests usually share an IP. With a rotating login, a new client per request gets a new IP each time; with a -sid- key, every connection keeps the same IP until the -ttl- runs out (1 to 60 minutes).

Each new client sends its first CONNECT without a login and repeats it with the login after the gateway's 407, one extra round trip per client; the gateway does not count that first try as a failed login. When you open a new client per request, send the login up front in a Proxy-Authorization header, as this example does. Java puts it on the CONNECT request only, never on the request to the site.

import java.net.InetSocketAddress;
import java.net.ProxySelector;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;
import java.util.Base64;

public class Sessions {
    static String exitIp(String login) throws Exception {
        String auth = "Basic " + Base64.getEncoder().encodeToString((login + ":PASSWORD").getBytes());
        HttpRequest req = HttpRequest.newBuilder(URI.create("https://api.ipify.org"))
            .header("Proxy-Authorization", auth) // goes with the CONNECT only, never to the site
            .timeout(Duration.ofSeconds(30))
            .build();
        try (HttpClient client = HttpClient.newBuilder() // a new client opens a new connection
                .proxy(ProxySelector.of(new InetSocketAddress("gate.aeonproxy.com", 7000)))
                .build()) {
            return client.send(req, HttpResponse.BodyHandlers.ofString()).body();
        }
    }

    public static void main(String[] args) throws Exception {
        System.setProperty("jdk.http.auth.tunneling.disabledSchemes", "");

        System.out.println(exitIp("LOGIN-cc-us") + " " + exitIp("LOGIN-cc-us")); // two IPs
        String sticky = "LOGIN-cc-us-sid-ab12cd34-ttl-30";
        System.out.println(exitIp(sticky) + " " + exitIp(sticky)); // one IP for up to 30 minutes
    }
}

SOCKS5: HttpURLConnection only

HttpClient ignores SOCKS proxies: given Proxy.Type.SOCKS, it connects directly, from your own IP, without an error.

HttpURLConnection supports SOCKS5 and asks the default Authenticator for the login, with the protocol SOCKS5. It resolves the site's name on your machine, so the DNS lookup leaves from your own network.

import java.net.Authenticator;
import java.net.HttpURLConnection;
import java.net.InetSocketAddress;
import java.net.PasswordAuthentication;
import java.net.Proxy;
import java.net.URI;

public class SocksExample {
    public static void main(String[] args) throws Exception {
        // the SOCKS5 login comes from the default Authenticator
        Authenticator.setDefault(new Authenticator() {
            @Override
            protected PasswordAuthentication getPasswordAuthentication() {
                if (!"SOCKS5".equals(getRequestingProtocol())) return null;
                return new PasswordAuthentication("LOGIN-cc-de", "PASSWORD".toCharArray());
            }
        });

        Proxy socks = new Proxy(Proxy.Type.SOCKS, InetSocketAddress.createUnresolved("gate.aeonproxy.com", 7001));
        HttpURLConnection conn = (HttpURLConnection) URI.create("https://api.ipify.org").toURL().openConnection(socks);
        conn.setConnectTimeout(30_000);
        conn.setReadTimeout(30_000);
        try (var in = conn.getInputStream()) {
            System.out.println(new String(in.readAllBytes()));
        }
    }
}

If it does not work

What you seeWhat to check
Status 407 with the right passwordBasic is still disabled for tunnels. Clear jdk.http.auth.tunneling.disabledSchemes before the first client is built.
IOException: too many authentication attempts. Limit: 3The login, the password, or a key that is not in the lists (a misspelled city, for example).
IOException: Tunnel failed, got: 402 or 502402: no traffic left on the product, or the sub-user reached its limit. 502: the exit failed; retry.
Tunnel failed, got: 42930 failed logins in a minute from your address: a wrong password or key, repeated by many threads. Java retries a wrong password, so each one counts several times. Fix the login and wait a minute.
Your own IP instead of the proxy'sA SOCKS proxy in the ProxySelector, which HttpClient ignores. Use port 7000.

Questions

Yes. A client built without .proxy(...) uses the default ProxySelector, which reads https.proxyHost and https.proxyPort (http. for http:// sites). The login still comes from an Authenticator or the header.

Yes: openConnection(new Proxy(Proxy.Type.HTTP, new InetSocketAddress("gate.aeonproxy.com", 7000))) with a default Authenticator that answers for RequestorType.PROXY, and the same Basic setting cleared for HTTPS sites.

Proxy questions? Ask support in the live chat.