# Proxy-Authenticate Header

> Learn how the Proxy-Authenticate header challenges clients for credentials when accessing resources through a proxy. Understand proxy authentication schemes.

Source: https://howhttpworks.com/headers/proxy-authenticate
Last reviewed: 2026-10-05

> **TL;DR:** When a proxy wants credentials, it answers `407 Proxy Authentication Required` and lists the schemes it accepts in `Proxy-Authenticate`. The client retries with `Proxy-Authorization`. It's the proxy-side twin of `401` plus `WWW-Authenticate`, which come from the origin server and need separate credentials.

The header tells the client which authentication scheme and parameters the proxy accepts. Every 407 a proxy generates must include at least one challenge. See [RFC 9110 §11.7.1](https://www.rfc-editor.org/rfc/rfc9110#section-11.7.1).

## How Proxy-Authenticate Works

For HTTPS through an HTTP/1.1 forward proxy, the client usually asks for a tunnel with CONNECT before any TLS handshake with the origin happens. The requests and responses on this page are trimmed examples.

```http
CONNECT api.example.com:443 HTTP/1.1
Host: api.example.com:443
```

If the proxy wants credentials first, it rejects the request with a challenge:

```http
HTTP/1.1 407 Proxy Authentication Required
Proxy-Authenticate: Basic realm="Corporate Proxy"
Content-Length: 0
```

Once the client authenticates, a successful CONNECT opens the tunnel and the origin TLS traffic flows through it. Plain HTTP requests through a forward proxy work differently: they use an absolute-form target such as `GET http://example.com/ HTTP/1.1`. See [RFC 9110 §9.3.6](https://www.rfc-editor.org/rfc/rfc9110#section-9.3.6) and [RFC 9112 §3.2.2](https://www.rfc-editor.org/rfc/rfc9112#section-3.2.2).

## Syntax

```text
Proxy-Authenticate: scheme [scheme-specific parameters]
```

Each scheme defines its own parameters, so `realm` isn't universal. If you parse the header yourself, remember that parameter values can contain commas, so splitting on commas won't reliably separate challenges.

A Basic challenge:

```http
Proxy-Authenticate: Basic realm="Corporate Proxy", charset="UTF-8"
```

The realm names a protection space so the client knows which credentials to use. Basic just base64-encodes the username and password, with no encryption at all. [RFC 7617](https://www.rfc-editor.org/rfc/rfc7617) defines its parameters.

### Multiple challenges and Digest parameters

A proxy can offer several challenges on separate field lines. This one offers Negotiate and Basic:

```http
Proxy-Authenticate: Negotiate
Proxy-Authenticate: Basic realm="Corporate Proxy"
```

The client picks a scheme it supports. Listing Negotiate first doesn't force anyone to use it. In curl, `--proxy-negotiate` authenticates to the proxy, while `--negotiate` authenticates to the origin. To let curl choose, pass `--proxy-anyauth` with your proxy credentials. The [curl proxy authentication options](https://curl.se/docs/manpage.html#--proxy-negotiate) document each layer.

Digest challenges carry algorithm-specific parameters. This one advertises SHA-256 and `qop=auth`:

```http
Proxy-Authenticate: Digest realm="proxy", nonce="proxy-generated-nonce", algorithm=SHA-256, qop="auth"
```

The client computes its response from this exact challenge and the request target. With qop, the nonce count and client nonce go into the hash too, so a response copied from another URI, or one that skips those inputs, will fail. If the proxy sends `opaque`, return it unchanged. [RFC 7616 §§3.3–3.4](https://www.rfc-editor.org/rfc/rfc7616#section-3.3) specifies these fields. Digest protects the password from casual sniffing, but it isn't a substitute for TLS.

## Testing Proxy-Authenticate

Point curl at your test proxy and look at the challenge without sending credentials:

```bash
curl --proxy http://proxy.example.com:3128 -v https://example.com/ -o /dev/null
```

Then let curl pick a supported scheme and prompt you for the password:

```bash
curl --proxy https://proxy.example.com:8443 \
  --proxy-anyauth --proxy-user proxyuser \
  https://example.com/ -o /dev/null
```

The `https://` proxy URL encrypts the hop between client and proxy. Swap in your own proxy hostname, port and certificate. [`--proxy-anyauth`](https://curl.se/docs/manpage.html#--proxy-anyauth) may cost an extra round trip while curl discovers the scheme, and it only helps if curl and the proxy share one.

## Getting Proxy-Authenticate right

Set proxy credentials in the client's proxy configuration, not in application code. Browsers make this explicit: Fetch forbids request headers that start with `Proxy-`, and it has no `proxy` option for picking a forward proxy. See the [Fetch Standard](https://fetch.spec.whatwg.org/#forbidden-request-header).

Watch the transport, too. If you talk to a proxy over plain HTTP, a Basic credential sent with CONNECT travels in the clear, even when the destination is HTTPS. It goes out before the destination TLS handshake starts.

## Proxy-Authenticate vs WWW-Authenticate

Getting through the proxy doesn't get you into the origin. A request inside an authenticated tunnel can still come back 401. In curl, `--proxy-user` holds your proxy credentials and `--user` holds your origin credentials. They're separate sets.

Basic and Digest are IETF-specified. Other schemes work only when both proxy and client support them, and how secure they are depends on the transport, the algorithm and the implementation.

## Server (Proxy) Implementation

Checking a password in an Express route doesn't make a forward proxy. A real one also handles CONNECT, validates destinations and keeps proxy credentials from leaking upstream. Use an existing proxy whose authentication and tunnel behavior you can test.

### Apache local forward proxy

For a local diagnostic proxy, bind to loopback and require credentials. You'll need Apache's proxy, proxy_http, proxy_connect, auth_basic, authn_file and authorization modules:

```apache
Listen 127.0.0.1:3128
<VirtualHost 127.0.0.1:3128>
    ProxyRequests On
    AllowCONNECT 443
    <Proxy "*">
        AuthType Basic
        AuthName "Local proxy"
        AuthBasicProvider file
        AuthUserFile /etc/apache2/proxy.htpasswd
        Require valid-user
    </Proxy>
</VirtualHost>
```

Create the credentials file:

```bash
htpasswd -c /etc/apache2/proxy.htpasswd proxyuser
```

Drop `-c` when adding users to an existing file. This listener speaks plain HTTP on loopback, so keep it local. Before serving remote users, add client-to-proxy TLS and network access restrictions. [Apache's proxy access documentation](https://httpd.apache.org/docs/2.4/mod/mod_proxy.html#access) explains why your access rules must cover CONNECT as well: it carries a host and port, not an origin path.

Test the challenge, then the authenticated tunnel:

```bash
curl --noproxy '' --proxy http://127.0.0.1:3128 -v https://example.com/ -o /dev/null
curl --noproxy '' --proxy http://127.0.0.1:3128 \
  --proxy-basic --proxy-user proxyuser https://example.com/ -o /dev/null
```

The first request gets a 407 challenge. The second prompts for the password and goes through. The origin might still reject the tunneled request on its own terms, but you've proven the proxy boundary works without writing a credential parser by hand.

## Debugging a persistent 407

Start with the advertised scheme and realm. If the proxy offers Digest and your client is forced to Basic, no password change will fix it. Let curl negotiate with `--proxy-anyauth`, or pick a scheme the proxy actually supports.

Next, check `NO_PROXY`. A request that bypasses the proxy never reaches the thing you're debugging. The commands above pass `--noproxy ''` to override any bypass settings. [curl documents this override](https://curl.se/docs/manpage.html#--noproxy).

With an HTTPS proxy there are two TLS peers: the proxy and the destination. A proxy certificate error happens before CONNECT authentication even starts, so treat it as a trust problem, not a credential one. Once CONNECT succeeds, the destination certificate gets verified separately. Do not disable both checks just to make a 407 easier to investigate.

For a plain HTTP destination, the client sends an absolute URI as the request target. Here the credentials are the example `user:pass`:

```http
GET http://example.com/ HTTP/1.1
Host: example.com
Proxy-Authorization: Basic dXNlcjpwYXNz
```

That's a different request form from HTTPS CONNECT. [RFC 9112 §3.2.2](https://www.rfc-editor.org/rfc/rfc9112#section-3.2.2) defines absolute-form for proxy requests.

## Related Headers

- [Proxy-Authorization](https://howhttpworks.com/headers/proxy-authorization)
- [WWW-Authenticate](https://howhttpworks.com/headers/www-authenticate)
- [Authorization](https://howhttpworks.com/headers/authorization)
- [407 Proxy Authentication Required](https://howhttpworks.com/status-codes/407)
