HTTP Digest Authentication
Digest auth is an HTTP challenge-response scheme that proves knowledge of a
password without sending it in cleartext, by hashing it together with a
server nonce. This reference lists every parameter in the WWW-Authenticate
challenge and the Authorization response, plus the exact hashing algorithm —
and a live computer that reproduces the response value.
Why Digest auth exists and when it is still relevant
Digest was defined in RFC 2617 (1999) and updated in RFC 7616 (2015) as a way to authenticate over HTTP without sending the plaintext password. It was designed for a world where TLS was expensive and optional. Today, TLS is ubiquitous and Bearer tokens are the preferred approach for APIs, so Digest auth is mostly found in legacy systems, embedded devices, IP cameras, routers, and protocol implementations that predate modern auth infrastructure. Understanding it is valuable for debugging those systems.
The full parameter set
WWW-Authenticate challenge (server → client)
| Parameter | Required | Meaning |
|---|---|---|
realm | Yes | A string identifying the protection space, shown to the user |
nonce | Yes | Server-generated opaque value, mixed into the response hash |
algorithm | No | Hash function: MD5 (default) or SHA-256 |
qop | No | Quality of protection: auth or auth-int; absence means legacy mode |
opaque | No | Opaque string the client must echo back unchanged |
domain | No | Space-separated list of URIs this challenge applies to |
stale | No | true if nonce expired but credentials were valid — retry without re-prompting |
charset | No | UTF-8 if username/password may use non-ASCII |
userhash | No | true to hash the username in the response |
Authorization response (client → server)
| Parameter | Meaning |
|---|---|
username | The username (or its hash if userhash=true) |
realm | Echoed from challenge |
nonce | Echoed from challenge |
uri | The request URI (must match the actual request) |
qop | Echoed if present |
nc | Nonce count — 8-digit hex, increments with each reuse of the nonce |
cnonce | Client nonce — client-generated random value when qop is present |
response | The computed digest (the key value) |
opaque | Echoed unchanged if present in challenge |
How the response is computed
The algorithm (RFC 7616) with qop=auth:
HA1 = H(username ":" realm ":" password)
HA2 = H(method ":" digestURI)
response = H(HA1 ":" nonce ":" nc ":" cnonce ":" qop ":" HA2)
H is the hash function from algorithm — MD5 by default or SHA-256. The legacy mode (no qop) uses the simpler form:
response = H(HA1 ":" nonce ":" HA2)
With qop=auth-int, body integrity is added:
HA2 = H(method ":" digestURI ":" H(entityBody))
Replay protection through nc and cnonce
The nonce count (nc) is an 8-hex-digit counter the client increments for every request that reuses the same server nonce. The server keeps track of which counts it has seen and rejects any repeated nc value, preventing captured responses from being replayed. The cnonce is a client-generated nonce that adds client-side randomness, preventing a malicious server from pre-computing responses for a guessed password using a known nonce.
When the server rotates the nonce (because it expired), it sets stale=true in the new challenge. A stale=true challenge means the credentials were cryptographically correct but the nonce aged out — the client should retry with the new nonce without asking the user for their password again.
Security context
MD5 Digest auth is widely considered cryptographically weak by modern standards — MD5 itself is broken for collision resistance. Even with SHA-256 (algorithm=SHA-256), Digest auth does not protect the request body (unless qop=auth-int, which adds buffering overhead) and is vulnerable to man-in-the-middle attacks without TLS. The live computer below uses Web Crypto for SHA-256 and a built-in MD5 implementation (Web Crypto intentionally omits MD5). Always run Digest over TLS; prefer Bearer tokens for new systems.