{"id":1070,"date":"2026-10-12T17:37:40","date_gmt":"2026-10-12T14:37:40","guid":{"rendered":"https:\/\/mexela.com\/blog\/python-httpx-proxy\/"},"modified":"2026-10-13T20:19:37","modified_gmt":"2026-10-13T17:19:37","slug":"python-httpx-proxy","status":"publish","type":"post","link":"https:\/\/mexela.com\/blog\/python-httpx-proxy\/","title":{"rendered":"Python HTTPX Proxy Setup: Authentication, SOCKS5 and Async Requests"},"content":{"rendered":"<p class=\"mexela-answer\">Use <code>proxy=<\/code> on an HTTPX <code>Client<\/code> or <code>AsyncClient<\/code>, keep TLS verification enabled, and verify a request from that same client. HTTPX 0.28.1 is the version used in this guide; examples using an older <code>proxies=<\/code> argument should be checked against their own release.<\/p>\n<p><strong>Reviewed and locally tested: October 12, 2026.<\/strong> Version and route observations below describe the stated test environment. A working local route does not establish a provider&#8217;s public exit, country, anonymity, speed, or uptime.<\/p>\n<h2 id=\"install\">Install the client and choose the protocol<\/h2>\n<pre><code class=\"language-bash\">python -m pip install &quot;httpx==0.28.1&quot;<\/code><\/pre>\n<p>For a SOCKS endpoint, install <code>httpx[socks]==0.28.1<\/code> instead. Our SOCKS test also used socksio 1.0.0. Pin the tested version for a reproducible diagnostic, then assess dependency updates under your application&#8217;s normal maintenance process.<\/p>\n<p>The proxy URL describes the connection to the proxy. An HTTPS destination can travel through an <code>http:\/\/<\/code> proxy using CONNECT; changing the destination to HTTPS does not automatically make the proxy endpoint <code>https:\/\/<\/code>. Match the supplied endpoint protocol. See <a href=\"https:\/\/www.python-httpx.org\/advanced\/proxies\/\">HTTPX proxy documentation<\/a> and <a href=\"\/blog\/http-https-socks5-proxies\/\">the protocol comparison<\/a>.<\/p>\n<h2 id=\"sync-client\">Make one explicit synchronous request<\/h2>\n<pre><code class=\"language-python\">import os, ssl\nimport httpx\n\ndef tls_context(ca_file=None):\n    return ssl.create_default_context(cafile=ca_file)\n\ndef httpx_request(url, proxy_url=None, ca_file=None):\n    with httpx.Client(proxy=proxy_url, trust_env=False, timeout=5.0,\n                      verify=tls_context(ca_file), follow_redirects=False) as client:\n        return client.get(url)\n\nresponse = httpx_request(os.environ[&quot;CHECK_URL&quot;], os.environ[&quot;PROXY_URL&quot;])\nprint({&quot;status&quot;: response.status_code})<\/code><\/pre>\n<p>Provide <code>CHECK_URL<\/code> and <code>PROXY_URL<\/code> through your process environment or secret manager. Choose a trusted HTTPS endpoint whose server-side observation you can inspect. Status 200 proves an HTTP response, while a destination log or observation endpoint establishes the route. Redirects are disabled so the diagnostic stays on the selected endpoint.<\/p>\n<p><code>trust_env=False<\/code> isolates this client from inherited proxy variables. The direct baseline uses the same function with <code>proxy_url=None<\/code>. The five-second setting bounds network inactivity; it is not a total wall-clock deadline for an entire multi-request job. See <a href=\"https:\/\/www.python-httpx.org\/advanced\/timeouts\/\">HTTPX timeout types<\/a>.<\/p>\n<h2 id=\"authentication\">Keep authentication outside code and logs<\/h2>\n<p>When an endpoint requires username\/password authentication, its URL can contain percent-encoded credentials. Build that value in memory, and avoid logging the URL, exception request objects, or environment dumps. Encoding changes URL syntax; it does not encrypt the credentials.<\/p>\n<pre><code class=\"language-python\">from urllib.parse import quote\n\nuser = quote(os.environ[&quot;PROXY_USER&quot;], safe=&quot;&quot;)\npassword = quote(os.environ[&quot;PROXY_PASSWORD&quot;], safe=&quot;&quot;)\nproxy_url = f&quot;http:\/\/{user}:{password}@proxy.example:8080&quot;<\/code><\/pre>\n<p>Replace the example host with the endpoint supplied for your account. An HTTP proxy connection does not itself encrypt Basic proxy authentication. Use a trusted path and the transport your provider supports. A proxy 407 is distinct from a destination 401 or 403; confirm which server rejected the request before changing credentials. Review <a href=\"\/blog\/proxy-authentication-username-password-vs-ip-auth\/\">proxy authentication methods<\/a>.<\/p>\n<h2 id=\"async\">Reuse an AsyncClient for async requests<\/h2>\n<pre><code class=\"language-python\">import asyncio\n\nasync def httpx_async_request(url, proxy_url=None, ca_file=None):\n    async with httpx.AsyncClient(proxy=proxy_url, trust_env=False, timeout=5.0,\n                                 verify=tls_context(ca_file), follow_redirects=False) as client:\n        return await client.get(url)\n\nresponse = asyncio.run(httpx_async_request(\n    os.environ[&quot;CHECK_URL&quot;], os.environ[&quot;PROXY_URL&quot;]))\nprint({&quot;status&quot;: response.status_code})<\/code><\/pre>\n<p>The snippet uses the imports and TLS helper above. For a service making many requests, move the client lifetime outside the per-request helper so connections can be reused. Start with one request; add bounded concurrency after authentication and routing are stable. <a href=\"https:\/\/www.python-httpx.org\/async\/\">HTTPX async guidance<\/a> explains the client lifecycle.<\/p>\n<h2 id=\"measured\">What the local tests actually established<\/h2>\n<table>\n<thead>\n<tr>\n<th>Check<\/th>\n<th>Observed result<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>Sync and async HTTP forwarding<\/td>\n<td>Owned loopback destination identified the authenticated proxy route<\/td>\n<\/tr>\n<tr>\n<td>Wrong proxy credentials<\/td>\n<td>Proxy returned 407; request did not reach the destination<\/td>\n<\/tr>\n<tr>\n<td>HTTPS CONNECT<\/td>\n<td>Untrusted disposable certificate rejected; request passed with that specific CA<\/td>\n<\/tr>\n<tr>\n<td>Authenticated SOCKS5 to HTTPS<\/td>\n<td>Owned destination identified the SOCKS route with certificate validation enabled<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>These requests ran on Windows with Python 3.12.14 and HTTPX 0.28.1. The destination did not receive a Proxy-Authorization header. The SOCKS fixture used an IP-literal destination, so this does not prove proxy-side hostname DNS, DNS privacy, or public exit behavior.<\/p>\n<h2 id=\"troubleshooting\">Troubleshoot one failure layer at a time<\/h2>\n<p>For an unexpected direct route, check that the request uses this configured client rather than a separate convenience call. For a connection error, confirm protocol, host, port and reachability. For a certificate error, investigate the approved CA chain and hostname; keep verification enabled. For a timeout, distinguish connect, read, write and pool waits before adding retries. Compare <a href=\"\/blog\/python-aiohttp-proxy\/\">aiohttp session setup<\/a> if you are migrating async code, or <a href=\"\/blog\/python-requests-proxy\/\">Requests configuration<\/a> for an existing Requests service.<\/p>\n<h2 id=\"faq\">Frequently asked questions<\/h2>\n<div class=\"mexela-faq\">\n<h3>Does HTTPX automatically use environment proxies?<\/h3>\n<p>It can when environment trust is enabled. These examples disable that inheritance to make the selected route explicit; <a href=\"\/blog\/http-proxy-https-proxy-no-proxy\/\">the environment-variable guide<\/a> shows measured differences between clients.<\/p>\n<h3>Can I use the same proxy with sync and async code?<\/h3>\n<p>Both client types accept a proxy endpoint. Test authentication and the destination observation in each client; sharing configuration does not prove that separate code paths used it.<\/p>\n<\/div>\n<h2 id=\"next-step\">Verify one client before increasing workload<\/h2>\n<p>Return to <a href=\"\/blog\/proxy-setup-developer-guides\/\">Proxy Setup and Developer Guides<\/a> for adjacent clients. Use <a href=\"\/blog\/test-if-your-proxy-is-working\/\">the proxy verification checklist<\/a> to record a direct baseline and the destination&#8217;s observation. When that is repeatable, compare <a href=\"\/proxy-locations\/\">Mexela proxy locations<\/a> against the actual destination and location requirements.<\/p>\n<p><!-- mexela-developer-kit-20261012:start --><\/p>\n<h2 id=\"developer-examples-download\">Download the developer examples<\/h2>\n<p><a href=\"\/blog\/wp-content\/uploads\/2026\/10\/mexela-developer-examples-20261012-v1.zip\">Download the developer examples ZIP<\/a> for the locally tested Python clients, environment checks, CI route-check files and native PHP cURL helper. The n8n workflow is a separate illustrative reference: it was not imported or executed in n8n. Read the included README for runtime versions, setup and the limits of each check.<\/p>\n<p>ZIP SHA-256: <code>3a43f7d1e6cbb9b2917dbcf88aaa8fe1a2733c33326187cb89c9a9119aad3e20<\/code>. Keep real proxy credentials and destination secrets in your approved secret store; they are absent from this archive. Start with one approved destination and compare its observation with a direct baseline.<\/p>\n<p><!-- mexela-developer-kit-20261012:end --><\/p>\n<h2 id=\"versioned-source-repository\">Versioned Python HTTPX source files<\/h2>\n<p>Use the <a href=\"\/blog\/proxy-code-examples-repository\/#python\">Python HTTPX folder in the public source repository<\/a> for the example, setup instructions, exact dependency versions and a sanitized test summary. The repository is a dated snapshot of owned examples; its loopback checks do not certify a commercial endpoint or every application configuration.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Configure HTTPX sync and async clients with an explicit proxy, safe authentication, optional SOCKS5 support, strict TLS and measured route checks.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[189],"tags":[],"_links":{"self":[{"href":"https:\/\/mexela.com\/blog\/wp-json\/wp\/v2\/posts\/1070"}],"collection":[{"href":"https:\/\/mexela.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/mexela.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/mexela.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/mexela.com\/blog\/wp-json\/wp\/v2\/comments?post=1070"}],"version-history":[{"count":0,"href":"https:\/\/mexela.com\/blog\/wp-json\/wp\/v2\/posts\/1070\/revisions"}],"wp:attachment":[{"href":"https:\/\/mexela.com\/blog\/wp-json\/wp\/v2\/media?parent=1070"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/mexela.com\/blog\/wp-json\/wp\/v2\/categories?post=1070"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/mexela.com\/blog\/wp-json\/wp\/v2\/tags?post=1070"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}