RFC 9421 vs draft-cavage: what changed?
RFC 9421 ("HTTP Message Signatures") replaced the expired draft-cavage-http-signatures with a standard that uses structured fields, introduces @-prefixed derived components, and clarifies the Signature-Input header semantics. The changes make signatures more interoperable, easier to debug, and future-proof for new HTTP features like digest fields and content negotiation.
If you implemented draft-cavage, you must migrate to RFC 9421 to stay compliant with modern HTTP stacks and avoid security warnings in browsers and proxies.
From strings to structured fields
The draft-cavage spec treated HTTP headers as raw strings. RFC 9421 moves to structured fields (RFC 8941), so every component is a typed item (string, token, byte sequence, or integer). This eliminates ambiguity in header parsing and lets you sign complex values like timestamps or lists without string munging.
Example: in draft-cavage you signed content-length: 123 as the literal string "content-length: 123". In RFC 9421 you sign the structured item content-length=123, preserving the integer type.
Derived components: the @-prefix revolution
RFC 9421 adds derived components, prefixed with @. These let you sign parts of the message that aren't headers, like the request target, the method, or the entire message body digest.
Common derived components:
- @method: the HTTP method (GET, POST, etc.)
- @target-uri: the full request URI
- @authority: the Host header value
- @request-response: ties a request to its response (for bidirectional signing)
- @query-param: signs a specific query parameter by name
These components are canonicalised per RFC 8941, so you don't have to worry about whitespace or case folding.
Signature-Input: what you actually signed
In draft-cavage, the Signature header contained the signature bytes, but the covered components were buried in the key metadata. RFC 9421 splits this into two headers:
Signature-Input: a structured field listing every component you signed, with parameters likekeyid,alg, andcreated. This header is human-readable and machine-verifiable.Signature: the raw signature bytes, base64-encoded.
This separation makes it trivial to debug which parts of the message were signed, and it lets you attach multiple signatures to the same message (for example, a short-lived Ed25519 signature and a long-term RSA signature).
Why migrate now
- Security warnings: Browsers and proxies flag draft-cavage signatures as non-standard. RFC 9421 is the IETF-approved way to sign HTTP messages.
- Digest fields: RFC 9421 integrates with RFC 9530 (Digest Fields), so you can sign the message body without reading it into memory. This is critical for large payloads like AI training corpora.
- Interoperability: Structured fields are the future of HTTP. Tools like OpenAPI and service meshes already expect them.
- Future-proofing: Derived components let you sign new HTTP features (for example,
@pathfor the request path) without breaking changes.
Do it with AlgoVoi
AlgoVoi's free, open (Apache-2.0) algovoi-rfc9421-verifier (v0.4.4) is a reference implementation of RFC 9421. It verifies both the Signature-Input and Signature headers, checks the covered components, and validates the signature against the key material.
Install:
- Python: pip install algovoi-rfc9421-verifier
- TypeScript: npm install @algovoi/rfc9421-verifier
Or try the hosted verifier at verify.algovoi.co.uk/rfc9421.
Next step
Start with the docs: docs.algovoi.co.uk/quickstart.