Find out where the request stopped
Start with one request to a URL you are allowed to use. A 403 means an HTTP server understood a request and refused it. With a proxy in the path, first find out which request was refused. Your client may have asked the proxy to open a tunnel before it could ask the destination for the page.
For HTTPS through an HTTP proxy, curl sends CONNECT with the destination host and port. A successful 2xx response opens the tunnel. curl then negotiates TLS with the destination and sends the HTTPS request. If the tunnel itself gets a 403, the destination has yet to receive that HTTPS request. If the HTTPS request gets a 403 after a successful tunnel, a server handling the destination request refused it. That server might be a CDN, an API gateway or the application.
A DNS failure, a timeout before connection or a TLS error can stop the request before either usable HTTP response arrives. Write down the client error alongside any status code. That gives you a starting point even when the application reports only a generic proxy error.
Read the tunnel and HTTPS status separately
In your shell, set PROXY_URL to your HTTP proxy URL and TARGET_URL to the exact HTTPS URL you are authorized to request. An example proxy format is http://USERNAME:PASSWORD@PROXY_HOST:PORT. Use your provider's configured host and port. Run the command in a private session. Proxy credentials passed on the command line may be visible to other local processes. This example sends one GET and leaves redirects unfollowed so you see the response from the URL you entered.
| CONNECT | HTTP | What to check next |
|---|---|---|
| 403 | 000 | The tunnel was refused. Check proxy-side restrictions and the destination host and port in your configuration. |
| 407 | 000 | The proxy asked for authentication. Check the proxy credentials and how the client sends them. |
| 200 | 403 | The tunnel opened and the destination path returned 403. Check the URL, account and access permissions. |
| 200 | 000 | The tunnel opened without a final HTTPS status. Read curl's error for a TLS failure, timeout or other transport problem. |
| 000 | 000 | Neither HTTP response was recorded. Read the client error and check the proxy address, DNS and connectivity. |
curl -q --silent --show-error --max-time 20 \
--noproxy '' --proxy "$PROXY_URL" \
--output /dev/null \
--write-out 'CONNECT=%{http_connect} HTTP=%{response_code}\n' \
"$TARGET_URL"000 is curl's display for a missing HTTP status. This command discards the body and prints the codes. curl can exit successfully after receiving a destination 403, so read both fields even when the exit status is zero.
When the tunnel is refused, check the proxy configuration
Compare the proxy scheme, hostname and port with your provider's connection instructions. Check whether your plan and network allow the destination host and port. In a managed network, the relevant policy might belong to an administrator rather than the proxy service you configured. A 403 on CONNECT alone gives you the stage of the refusal. The policy or log entry tells you why.
If you get 407, check the proxy username and password or the IP authorization settings your provider documents. The proxy and the destination each have their own authentication. An API token for the destination belongs in the destination request. Putting it in the proxy's credentials field will not authenticate you to the API.
The curl example clears its no-proxy list for this one diagnostic. If your app behaves differently, check whether its proxy settings, environment or exclusion list send that URL along another route. Use a harmless, allowed endpoint to confirm that the proxy works for a basic request, then compare that result with the failing URL. A working test endpoint confirms the route for that endpoint.
When the destination refuses the request, check what it expects
Check the exact hostname, path and method. A browser may open a signed-in dashboard while your script calls a different API endpoint with different permissions. Use the site's documented API or client and verify that the account can access that resource. Check the token's scope, the account or workspace it belongs to and any allowlist your team controls.
If policy permits a direct connection, compare one direct request to the same endpoint using the same method and authorized credentials. A 403 on both paths gives you a reason to check shared details such as the URL and account permissions first. If only the proxied request gets a 403, compare what actually reached the destination. Egress address, client configuration or a destination policy may differ. If you own the destination, look up the request in its logs before changing anything.
In a hypothetical catalog check, the proxy opens the tunnel with CONNECT=200. The catalog API then replies HTTP=403. Its administrator checks the request ID and finds that the service account has access to a staging catalog while the URL points to production. The operator corrects the environment URL for the approved task. The proxy connection already worked.
If the destination's policy refuses the traffic, stop and use its approved API, ask for access or contact the site owner. Repeating the same request with unchanged permissions rarely gives you more evidence. For a collection job, record the failed source and keep that response out of the dataset.
What to record when the two codes are unavailable
A SOCKS5 handshake does not produce an HTTP CONNECT response. For plain HTTP through an HTTP proxy, the proxy and destination can each generate an HTTP response on the same request path. In these cases, look at the client error, any safe request ID and the logs you can legitimately access. Treat a branded error page or a response header as a clue and confirm it against logs when possible.
For support, share the time with its time zone, the destination hostname, the method, the configured proxy protocol and the two status codes if you have them. Add a request ID or a short, sanitized error. Remove passwords, authorization headers, cookies and private URL parameters before sending any diagnostic output.
- HTTP status and tunnel semantics: RFC 9110, sections 9.3.6, 15.5.4 and 15.5.8 (https://www.rfc-editor.org/rfc/rfc9110.html).
- curl options and status fields: curl command-line manual (https://curl.se/docs/manpage.html).
