An API gateway can verify a signature and still authorize the wrong request. RFC 9421 defines HTTP Message Signatures so that a signer can sign selected components of a request or response, and a verifier can reconstruct the same signed data later. The hard part is not the cryptographic signature. It is deciding which parts of the HTTP message are covered and ensuring both sides derive them the same way.

RFC 9421 introduces a signature base built from component identifiers and their values. A component can be a header, a derived field such as @method or @target-uri, or another item named in @signature-input. The verifier parses Signature-Input, reconstructs the base, and checks the Signature header. The specification's canonicalization rules exist because HTTP messages pass through clients, proxies, load balancers, and application frameworks that may normalize field values, paths, or connection metadata.

A signature over content-digest protects a representation only if the verifier also calculates and compares that digest. Signing @method and @target-uri does not automatically protect query parameters that a downstream router uses, a different host interpretation made by a proxy, or an authorization decision based on a header that was not signed. The verifier must produce an authorization decision from the same message interpretation that the signature covers.

There are several practical failure modes.

  1. 1.

    The signer covers a header name, but an intermediary combines or rewrites duplicate headers.

  2. 2.

    The verifier reconstructs the target URI from its own external host and path, while the signer used the client-visible URI.

  3. 3.

    The signed content digest is present, but the application reads a different body after decompression or transformation.

  4. 4.

    The application trusts an unsigned tenant, role, or routing header and never includes it in the signature policy.

  5. 5.

    The signature is valid, but the verifier accepts an expired key, the wrong key identifier, or a signature label that does not match policy.

The control is not a single header. It is a verifier policy that lists required components, allowed signature algorithms, key resolution, expiration, and the relationship between the covered message and the resource being authorized. A gateway that terminates TLS and passes a normalized request to the application should make that normalized form the signing contract. If multiple representations are possible, the verifier should reject ambiguity rather than guess which one the signer intended.

Testing should use the actual proxy chain. Send requests with different host headers, repeated fields, unusual path encodings, chunked bodies, and content encodings. Capture the reconstructed signature base on both sides and compare it. Then remove one protected component at a time and confirm that the service rejects the request. A test that only proves a valid signature is accepted misses the more important case: whether a modified request can still pass.

HTTP Message Signatures can make integrity an explicit part of an API contract. The design needs a canonical message shape, a complete component policy, and a verification path that cannot be bypassed by a second parser. Without those pieces, a valid signature proves only that some bytes were signed.

References