Signature

Request and response integrity verification is achieved through the HTTP Signature header, which carries one or more cryptographic signatures over message components as base64 byte sequences.

Usage

The Signature header carries cryptographic signatures over HTTP messages. A sender signs selected parts of a request or response, such as the method, path, specific headers, or status code, and places the resulting signature in this header. Each signature is labeled with an identifier matching a corresponding entry in the Signature-Input header, which describes what was signed and with which parameters.

This mechanism applies to both requests and responses. On the request side, API clients sign outgoing calls to prove identity, and crawlers sign requests to authorize themselves against origin servers. On the response side, servers sign their replies so clients or intermediaries verify content integrity.

Multiple independent signatures are allowed on a single message. Each uses a distinct label, enabling scenarios where a client signs a request and a proxy adds a second signature without replacing the first.

Values

Signature labels

The value is a Dictionary Structured Field. Each entry pairs a label with a base64-encoded byte sequence wrapped in colon delimiters. Labels are arbitrary identifiers chosen by the signer. Every label in the Signature header must have a matching label in the Signature-Input header.

Signature: sig1=:base64value:

Multiple signatures are comma-separated.

Signature: sig1=:base64value:, sig2=:base64value:

Example

A client signs a GET request to an API endpoint. The signature covers the HTTP method, authority, and path, along with the date header. The label sig1 ties this signature to its metadata in Signature-Input.

GET /api/resource HTTP/1.1
Host: api.example.re
Date: Thu, 13 Feb 2025 10:30:00 GMT
Signature-Input: sig1=("@method" "@authority" "@path" "date");alg="ed25519";created=1739442600;keyid="client-key-ed25519"
Signature: sig1=:dGhpcyBpcyBhIHNhbXBsZSBzaWduYXR1cmUgdmFsdWU=:

A server signs a response to let the client verify content integrity. The label resp covers the status code, Content-Type, and a content digest. The ;req flag on @authority and @method binds the response signature to the original request.

HTTP/1.1 200 OK
Content-Type: application/json
Content-Digest: sha-256=:X48E9qOokqqrvdts8nOJRJN3OWDUoyWxBf7kbu9DBPE=:
Signature-Input: resp=("@status" "content-type" "content-digest" "@authority";req "@method";req);alg="ed25519";created=1739442601;keyid="server-key-ed25519"
Signature: resp=:dGhpcyBpcyBhIHNhbXBsZSByZXNwb25zZSBzaWduYXR1cmU=:

A message with two independent signatures appears when a proxy and an origin client each sign the request separately. The proxy covers the method and authority with HMAC-SHA256, while the origin client covers additional components with Ed25519.

Signature-Input: proxy=("@method" "@authority");alg="hmac-sha256";created=1739353800;keyid="proxy-secret", origin=("@method" "@authority" "@path" "content-type" "content-digest");alg="ed25519";created=1739353799;keyid="origin-client-key"
Signature: proxy=:cHJveHkgc2lnbmF0dXJl:, origin=:b3JpZ2luIHNpZ25hdHVyZQ==:

Reading the modern header safely

The value is a structured-field dictionary whose members are byte sequences, so each signature arrives base64-wrapped in colons under a label. The colons are delimiters belonging to the syntax, the base64 uses the standard alphabet with padding, and a label present here without a matching Signature-Input member is a hard verification failure rather than something to skip.

The label system makes signatures additive. Several signers coexist in one message, and the documented pattern has a reverse proxy adding a second signature over a rewritten request, covering the client's original signature among the components, a short expiry bounding how long the proxy vouches for the message.

Telling the generations apart has an official rule: detect Signature-Input first. Present, and every Signature member parses under the modern specification. Absent, and a lone Signature header belongs to the older draft-cavage family, which packed the covered-field list inside the header itself. Sniffing the value text instead of checking for the companion field is the wrong-format bug waiting to happen.

Trailers are permitted and discouraged in the same breath, since intermediaries legally drop trailers, and a stripped signature downgrades a signed message to an unsigned one silently.

See also

Last updated: August 17, 2026