Skip to main content

HTTP Signature Keys
draft-hardt-httpbis-signature-key-07

Document Type Active Internet-Draft (candidate for httpbis WG)
Authors Dick Hardt , Thibault Meunier
Last updated 2026-07-04
RFC stream Internet Engineering Task Force (IETF)
Intended RFC status (None)
Formats
Additional resources Mailing list discussion
Stream WG state Call For Adoption By WG Issued
Document shepherd (None)
IESG IESG state I-D Exists
Consensus boilerplate Unknown
Telechat date (None)
Responsible AD (None)
Send notices to (None)
draft-hardt-httpbis-signature-key-07
HTTP                                                            D. Hardt
Internet-Draft                                                     Hellō
Intended status: Standards Track                              T. Meunier
Expires: 5 January 2027                                       Cloudflare
                                                             4 July 2026

                          HTTP Signature Keys
                  draft-hardt-httpbis-signature-key-07

Abstract

   This document defines two HTTP header fields and one Accept-Signature
   parameter for use with HTTP Message Signatures as defined in RFC
   9421.  The Signature-Key request header distributes public keys used
   to verify signatures, with six initial key distribution schemes:
   pseudonymous inline keys (hwk), self-issued key delegation via JWK
   Thumbprint JWTs (jkt-jwt), identified signers with JWKS URI discovery
   (jwks_uri), JWT-based delegation (jwt), self-issued JWTs (self-jwt),
   and X.509 certificate chains (x509).  The sigkey parameter extends
   Accept-Signature (RFC 9421 Section 5) to indicate the type of
   Signature-Key the server requires.  The Signature-Error response
   header provides structured error information when signature
   verification fails.  Together, these mechanisms enable flexible trust
   models ranging from privacy-preserving pseudonymous verification to
   horizontally-scalable delegated authentication and PKI-based identity
   chains.

Discussion Venues

   _Note: This section is to be removed before publishing as an RFC._

   Source for this draft and an issue tracker can be found at
   https://github.com/dickhardt/signature-key
   (https://github.com/dickhardt/signature-key).

Status of This Memo

   This Internet-Draft is submitted in full conformance with the
   provisions of BCP 78 and BCP 79.

   Internet-Drafts are working documents of the Internet Engineering
   Task Force (IETF).  Note that other groups may also distribute
   working documents as Internet-Drafts.  The list of current Internet-
   Drafts is at https://datatracker.ietf.org/drafts/current/.

Hardt & Meunier          Expires 5 January 2027                 [Page 1]
Internet-Draft               Signature-Keys                    July 2026

   Internet-Drafts are draft documents valid for a maximum of six months
   and may be updated, replaced, or obsoleted by other documents at any
   time.  It is inappropriate to use Internet-Drafts as reference
   material or to cite them other than as "work in progress."

   This Internet-Draft will expire on 5 January 2027.

Copyright Notice

   Copyright (c) 2026 IETF Trust and the persons identified as the
   document authors.  All rights reserved.

   This document is subject to BCP 78 and the IETF Trust's Legal
   Provisions Relating to IETF Documents (https://trustee.ietf.org/
   license-info) in effect on the date of publication of this document.
   Please review these documents carefully, as they describe your rights
   and restrictions with respect to this document.  Code Components
   extracted from this document must include Revised BSD License text as
   described in Section 4.e of the Trust Legal Provisions and are
   provided without warranty as described in the Revised BSD License.

Table of Contents

   1.  Conventions and Definitions . . . . . . . . . . . . . . . . .   3
   2.  Introduction  . . . . . . . . . . . . . . . . . . . . . . . .   4
   3.  Signature-Key HTTP Request Header . . . . . . . . . . . . . .   5
     3.1.  Label Consistency . . . . . . . . . . . . . . . . . . . .   6
     3.2.  Multiple Signatures . . . . . . . . . . . . . . . . . . .   6
     3.3.  Header Web Key (hwk)  . . . . . . . . . . . . . . . . . .   7
     3.4.  JKT JWT Self-Issued Key Delegation (jkt-jwt)  . . . . . .   8
     3.5.  JWKS URI Discovery (jwks_uri) . . . . . . . . . . . . . .  12
     3.6.  JWT Confirmation Key (jwt)  . . . . . . . . . . . . . . .  13
     3.7.  Self-Issued JWT (self-jwt)  . . . . . . . . . . . . . . .  15
     3.8.  X.509 Certificates (x509) . . . . . . . . . . . . . . . .  17
   4.  Accept-Signature sigkey Parameter . . . . . . . . . . . . . .  18
     4.1.  Parameter Definition  . . . . . . . . . . . . . . . . . .  18
     4.2.  Label Binding . . . . . . . . . . . . . . . . . . . . . .  18
     4.3.  Response Status Codes . . . . . . . . . . . . . . . . . .  19
     4.4.  sigkey Semantics  . . . . . . . . . . . . . . . . . . . .  20
       4.4.1.  jkt . . . . . . . . . . . . . . . . . . . . . . . . .  20
       4.4.2.  uri . . . . . . . . . . . . . . . . . . . . . . . . .  20
       4.4.3.  x509  . . . . . . . . . . . . . . . . . . . . . . . .  20
     4.5.  Incremental Adoption  . . . . . . . . . . . . . . . . . .  20
     4.6.  Coexistence with WWW-Authenticate . . . . . . . . . . . .  21
     4.7.  Examples  . . . . . . . . . . . . . . . . . . . . . . . .  21
     4.8.  Client Processing . . . . . . . . . . . . . . . . . . . .  22
   5.  Signature-Error HTTP Response Header  . . . . . . . . . . . .  22
     5.1.  Header Structure  . . . . . . . . . . . . . . . . . . . .  23

Hardt & Meunier          Expires 5 January 2027                 [Page 2]
Internet-Draft               Signature-Keys                    July 2026

     5.2.  Response Body . . . . . . . . . . . . . . . . . . . . . .  23
     5.3.  Access Denied . . . . . . . . . . . . . . . . . . . . . .  23
     5.4.  Error Codes . . . . . . . . . . . . . . . . . . . . . . .  24
       5.4.1.  unsupported_algorithm . . . . . . . . . . . . . . . .  24
       5.4.2.  invalid_signature . . . . . . . . . . . . . . . . . .  24
       5.4.3.  invalid_input . . . . . . . . . . . . . . . . . . . .  24
       5.4.4.  invalid_request . . . . . . . . . . . . . . . . . . .  24
       5.4.5.  invalid_key . . . . . . . . . . . . . . . . . . . . .  25
       5.4.6.  unknown_key . . . . . . . . . . . . . . . . . . . . .  25
       5.4.7.  invalid_jwt . . . . . . . . . . . . . . . . . . . . .  25
       5.4.8.  expired_jwt . . . . . . . . . . . . . . . . . . . . .  25
   6.  Security Considerations . . . . . . . . . . . . . . . . . . .  25
     6.1.  Key Validation  . . . . . . . . . . . . . . . . . . . . .  25
     6.2.  Caching and Performance . . . . . . . . . . . . . . . . .  26
     6.3.  Scheme-Specific Risks . . . . . . . . . . . . . . . . . .  26
     6.4.  Algorithm Selection . . . . . . . . . . . . . . . . . . .  28
     6.5.  Signature-Key Integrity . . . . . . . . . . . . . . . . .  28
   7.  Privacy Considerations  . . . . . . . . . . . . . . . . . . .  29
     7.1.  Pseudonymity vs. Identity . . . . . . . . . . . . . . . .  29
     7.2.  Key Discovery Tracking  . . . . . . . . . . . . . . . . .  29
     7.3.  JWT Contents  . . . . . . . . . . . . . . . . . . . . . .  30
   8.  IANA Considerations . . . . . . . . . . . . . . . . . . . . .  30
     8.1.  HTTP Field Name Registration  . . . . . . . . . . . . . .  30
     8.2.  Signature-Key Scheme Registry . . . . . . . . . . . . . .  30
       8.2.1.  Registration Procedure  . . . . . . . . . . . . . . .  31
       8.2.2.  Initial Registry Contents . . . . . . . . . . . . . .  31
       8.2.3.  Registration Template . . . . . . . . . . . . . . . .  31
     8.3.  HTTP Signature Metadata Parameters  . . . . . . . . . . .  31
     8.4.  URN Sub-namespace Registration  . . . . . . . . . . . . .  32
     8.5.  Signature Error Code Registry . . . . . . . . . . . . . .  32
       8.5.1.  Initial Registry Contents . . . . . . . . . . . . . .  32
   9.  Document History  . . . . . . . . . . . . . . . . . . . . . .  33
   10. Acknowledgments . . . . . . . . . . . . . . . . . . . . . . .  34
   11. References  . . . . . . . . . . . . . . . . . . . . . . . . .  35
     11.1.  Normative References . . . . . . . . . . . . . . . . . .  35
     11.2.  Informative References . . . . . . . . . . . . . . . . .  36
   Appendix A.  Design Rationale . . . . . . . . . . . . . . . . . .  37
     A.1.  Why jwks_uri Instead of Inline JWKS?  . . . . . . . . . .  37
     A.2.  Why a Separate Header?  . . . . . . . . . . . . . . . . .  37
     A.3.  Why Schemes Instead of Just a Key and Key ID? . . . . . .  38
     A.4.  Why Strings Instead of Byte Sequences for hwk?  . . . . .  39
   Authors' Addresses  . . . . . . . . . . . . . . . . . . . . . . .  39

1.  Conventions and Definitions

   {::boilerplate bcp14-tagged}

Hardt & Meunier          Expires 5 January 2027                 [Page 3]
Internet-Draft               Signature-Keys                    July 2026

2.  Introduction

   HTTP Message Signatures [RFC9421] provides a powerful mechanism for
   creating and verifying digital signatures over HTTP messages.  To
   verify a signature, the verifier needs the signer's public key.
   While RFC 9421 defines signature creation and verification
   procedures, it intentionally leaves key distribution to application
   protocols, recognizing that different deployments have different
   trust requirements.

   This document defines:

   *  *Signature-Key* (Signature-Key HTTP Request Header (#signature-
      key-http-request-header)) — a request header that distributes
      public keys for HTTP Message Signature verification.  The header
      supports six schemes, each designed for different trust models and
      operational requirements:

      1.  *Header Web Key (hwk)* - Self-contained public keys for
          pseudonymous verification
      2.  *JKT JWT (jkt-jwt)* - Self-issued key delegation via JWK
          Thumbprint JWTs ("jacket jot")
      3.  *JWKS URI (jwks_uri)* - Identified signers with key discovery
          via metadata
      4.  *JWT (jwt)* - Delegated keys embedded in signed JWTs for
          horizontal scale
      5.  *Self-Issued JWT (self-jwt)* - Self-signed JWTs where the
          signer and issuer are the same party
      6.  *X.509 (x509)* - Certificate-based verification with PKI trust
          chains

   Additional schemes may be defined through the IANA registry
   established by this document.

   *  *sigkey* (Accept-Signature sigkey Parameter (#accept-signature-
      sigkey-parameter)) — a parameter for the Accept-Signature header
      ([RFC9421], Section 5) that indicates the type of Signature-Key
      the server requires.  This extends RFC 9421's existing mechanism
      for requesting signatures rather than defining a new header.

   *  *Signature-Error* (Signature-Error HTTP Response Header
      (#signature-error-http-response-header)) — a response header that
      provides structured error information when signature verification
      fails, enabling clients to diagnose and correct signing issues.

   The Signature-Key header works in conjunction with the Signature-
   Input and Signature headers defined in RFC 9421, using matching
   labels to correlate signature metadata with keying material.

Hardt & Meunier          Expires 5 January 2027                 [Page 4]
Internet-Draft               Signature-Keys                    July 2026

   The mechanisms in this document were designed as general-purpose
   building blocks and are used by other specifications.  In the AAuth
   protocol [I-D.hardt-oauth-aauth-protocol], all parties communicate
   using Signature-Key to distribute the keys that verify their signed
   requests.  Email Verification [I-D.hardt-email-verification] uses the
   hwk scheme to convey the browser's public key so the issuer can bind
   it into the verification token it issues.  Additional protocols can
   adopt these mechanisms without further coordination.

3.  Signature-Key HTTP Request Header

   The Signature-Key header provides the public key or key reference
   needed to verify an HTTP Message Signature.  It is a Structured Field
   Dictionary [RFC8941] keyed by signature label, where each member
   describes how to obtain the verification key for the corresponding
   signature.

   *Format:*

   Signature-Key: <label>=<scheme>;<parameters>...

   Where: - <label> (dictionary key) matches the label in Signature-
   Input and Signature headers - <scheme> (token) identifies the key
   distribution scheme - <parameters> are semicolon-separated key-value
   pairs whose values are structured field strings or byte sequences,
   varying by scheme

   Multiple keys are comma-separated per the dictionary format.  See
   [RFC8941] for definitions of dictionary, token, string, and byte
   sequence.

   *Example:*

Signature-Input: sig=("@method" "@authority" "@path" "signature-key"); created=1732210000
Signature: sig=:MEQCIA5...
Signature-Key: sig=hwk;kty="OKP";crv="Ed25519";x="JrQLj..."

   *Label Correlation:*

   Labels are correlated by equality of label names across Signature-
   Input, Signature, and Signature-Key. Signature-Key is a dictionary
   keyed by label; Signature-Input and Signature are the sources of what
   signatures are present; Signature-Key provides keying material for
   those labels.

   Verifiers MUST:

Hardt & Meunier          Expires 5 January 2027                 [Page 5]
Internet-Draft               Signature-Keys                    July 2026

   1.  Parse Signature-Input and Signature per RFC 9421 and obtain the
       set of signature labels present.  The verifier determines which
       labels it is attempting to verify based on application context
       and RFC 9421 processing.

   2.  Parse Signature-Key as a Structured Fields Dictionary

   3.  For each label being verified, select the Signature-Key
       dictionary member with the same name

   4.  If the Signature-Key header is present and the verifier is
       attempting to verify a label using it, but the corresponding
       dictionary member is missing, verification for that signature
       MUST fail

   |  *Note:* A verifier might choose to verify only a subset of labels
   |  present (e.g., the application-required signature); labels not
   |  verified can be ignored.

   Signatures whose keys are distributed through mechanisms outside this
   specification (e.g., pre-configured keys, out-of-band key exchange)
   are out of scope.  A Signature-Key header is not required for such
   signatures, and verifiers MAY use application-specific means to
   obtain the verification key.

3.1.  Label Consistency

   If a label appears in Signature or Signature-Input, and the verifier
   attempts to verify it using Signature-Key, the corresponding member
   MUST exist in Signature-Key. If Signature-Key contains members for
   labels not being verified, verifiers MAY ignore them.

3.2.  Multiple Signatures

   The dictionary format supports multiple signatures per message.  Each
   signature has its own dictionary member keyed by its unique label:

Signature-Input: sig1=(... "signature-key"), sig2=(... "signature-key")
Signature: sig1=:...:, sig2=:...:
Signature-Key: sig1=jwt;jwt="eyJ...", sig2=jwks_uri;id="https://example.com";dwk="eg-config";kid="k1"

Hardt & Meunier          Expires 5 January 2027                 [Page 6]
Internet-Draft               Signature-Keys                    July 2026

   Most deployments SHOULD use a single signature.  When multiple
   signatures are required, the complete Signature-Key header
   (containing all keys) MUST be populated before any signature is
   created, and each signature MUST cover signature-key.  This ensures
   all signatures protect the integrity of all key material.  See
   Signature-Key Integrity (#signature-key-integrity) in Security
   Considerations.  Alternative key distribution mechanisms outside this
   specification may be used for scenarios requiring independent
   signature addition.

3.3.  Header Web Key (hwk)

   The hwk scheme provides a self-contained public key inline in the
   header, enabling pseudonymous verification without key discovery.
   The parameter names and values correspond directly to the JWK
   parameters defined in [RFC7517].

   *Parameters by key type:*

   OKP (Octet Key Pair):

   *  kty (REQUIRED, String) - "OKP"

   *  crv (REQUIRED, String) - Curve name (e.g., "Ed25519")

   *  x (REQUIRED, String) - Public key value

   Signature-Key: sig=hwk;kty="OKP";crv="Ed25519";x="JrQLj5P..."

   EC (Elliptic Curve):

   *  kty (REQUIRED, String) - "EC"

   *  crv (REQUIRED, String) - Curve name (e.g., "P-256", "P-384")

   *  x (REQUIRED, String) - X coordinate

   *  y (REQUIRED, String) - Y coordinate

Signature-Key: sig=hwk;kty="EC";crv="P-256";x="f83OJ3D...";y="x_FEzRu..."

   RSA:

   *  kty (REQUIRED, String) - "RSA"

   *  n (REQUIRED, String) - Modulus

   *  e (REQUIRED, String) - Exponent

Hardt & Meunier          Expires 5 January 2027                 [Page 7]
Internet-Draft               Signature-Keys                    July 2026

   Signature-Key: sig=hwk;kty="RSA";n="0vx7agoebGcQ...";e="AQAB"

   *Constraints:*

   *  The alg parameter MUST NOT be present (algorithm is derived from
      the key type and curve)

   *  The kid parameter SHOULD NOT be used

   *Use cases:*

   *  Privacy-preserving agents that avoid identity disclosure

   *  Experimental or temporary access without registration

   *  Rate limiting and reputation building on a per-key basis

3.4.  JKT JWT Self-Issued Key Delegation (jkt-jwt)

   The jkt-jwt scheme (pronounced "jacket jot") provides self-issued key
   delegation using a JWT whose signing key is embedded in the JWT
   header.  This enables devices with hardware-backed secure enclaves to
   delegate signing authority to ephemeral keys, avoiding the
   performance cost of repeated enclave operations while maintaining a
   cryptographic chain of trust rooted in the enclave key.

   Many devices — mobile phones, laptops, IoT hardware — include secure
   enclaves or trusted execution environments (e.g., Apple Secure
   Enclave, Android StrongBox, TPM) that can generate and store private
   keys with strong protection guarantees.  However, signing operations
   using these enclaves are comparatively slow and may require user
   interaction (biometric confirmation, PIN entry).

   For HTTP Message Signatures, where every request requires a
   signature, this creates a tension between security and performance.
   The jkt-jwt scheme resolves this by allowing the enclave key to sign
   a JWT that delegates authority to a faster ephemeral key:

   1.  The enclave generates a long-lived key pair (the identity key)
   2.  The device generates an ephemeral key pair in software (the
       signing key)
   3.  The enclave signs a JWT binding the ephemeral key via the cnf
       claim
   4.  HTTP requests are signed with the fast ephemeral key
   5.  The JWT proves the ephemeral key was authorized by the enclave
       key

Hardt & Meunier          Expires 5 January 2027                 [Page 8]
Internet-Draft               Signature-Keys                    July 2026

   The enclave key's JWK Thumbprint URI (urn:jkt:<hash-
   algorithm>:<thumbprint>) serves as a stable, pseudonymous device
   identity.  Verifiers build trust in this identity over time (TOFU —
   Trust On First Use [RFC7435]).

   *Parameters:*

   *  jwt (REQUIRED, String) - Compact-serialized JWT

   *JWT requirements:*

   Header:

   *  typ (REQUIRED) - Identifies the thumbprint hash algorithm.
      Defined values: jkt-s256+jwt (SHA-256), jkt-s512+jwt (SHA-512).
      Implementations MUST support jkt-s256+jwt and MAY support
      additional algorithms.

   *  alg (REQUIRED) - Signature algorithm used by the enclave key

   *  jwk (REQUIRED) - JWK public key of the enclave/identity key (the
      key that signed this JWT)

   Payload:

   *  iss (REQUIRED) - JWK Thumbprint URI of the signing key, in the
      format urn:jkt:<hash-algorithm>:<thumbprint> where the thumbprint
      is computed per [RFC7638].  The hash algorithm in the URN MUST
      match the algorithm indicated by the JWT typ.  The verifier knows
      the hash algorithm from the typ it accepted, computes the
      thumbprint of the header jwk, prepends the known urn:jkt:<hash-
      algorithm>: prefix, and compares to iss by string equality.

   *  iat (REQUIRED) - Issued-at timestamp

   *  exp (REQUIRED) - Expiration timestamp

   *  cnf (REQUIRED) - Confirmation claim [RFC7800] containing jwk: the
      ephemeral public key delegated for HTTP message signing

   The sub claim is not used.  The identity is the enclave key itself,
   fully represented by the iss thumbprint.

   *JWT Type Values:*

   The typ value encodes both the purpose and the thumbprint hash
   algorithm:

Hardt & Meunier          Expires 5 January 2027                 [Page 9]
Internet-Draft               Signature-Keys                    July 2026

           +==============+================+==================+
           | typ          | Hash Algorithm | iss prefix       |
           +==============+================+==================+
           | jkt-s256+jwt | SHA-256        | urn:jkt:sha-256: |
           +--------------+----------------+------------------+
           | jkt-s512+jwt | SHA-512        | urn:jkt:sha-512: |
           +--------------+----------------+------------------+

                                 Table 1

   The jkt- prefix indicates a self-issued delegation JWT: the signing
   key is embedded in the JWT header as a JWK, the issuer is identified
   by the key's thumbprint, and the JWT delegates signing authority to
   the key in the cnf claim.  The suffix (s256, s512) identifies the
   hash algorithm used for the thumbprint.  The typ and iss prefix MUST
   be consistent.

   These types are independent of the Signature-Key header and MAY be
   used in other contexts where self-issued key delegation is needed.
   Additional hash algorithms can be supported by registering new typ
   values following the jkt-<alg>+jwt pattern.

   *Example:*

   Signature-Key: sig=jkt-jwt;jwt="eyJ..."

   JWT header:

   {
     "typ": "jkt-s256+jwt",
     "alg": "ES256",
     "jwk": {
       "kty": "EC",
       "crv": "P-256",
       "x": "f83OJ3D2xF1Bg8vub9tLe1gHMzV76e8Tus9uPHvRVEU",
       "y": "x_FEzRu9m36HLN_tue659LNpXW6pCyStikYjKIWI5a0"
     }
   }

   JWT payload:

Hardt & Meunier          Expires 5 January 2027                [Page 10]
Internet-Draft               Signature-Keys                    July 2026

   {
     "iss": "urn:jkt:sha-256:NzbLsXh8uDCcd-6MNwXF4W_7noWXFZAfHkxZsRGC9Xs",
     "iat": 1732210000,
     "exp": 1732296400,
     "cnf": {
       "jwk": {
         "kty": "OKP",
         "crv": "Ed25519",
         "x": "JrQLj5P_89iXES9-vFgrIy29clF9CC_oPPsw3c5D0bs"
       }
     }
   }

   In this example, the enclave holds a P-256 key (signed via hardware)
   and delegates to an Ed25519 ephemeral key (signed in software).  The
   identity is urn:jkt:sha-256:NzbLsXh8uDCcd-
   6MNwXF4W_7noWXFZAfHkxZsRGC9Xs.

   The stable (enclave) key algorithm in the JWT alg header is
   determined by what the enclave hardware supports.  This document's
   example uses ES256 with a P-256 stable key delegating to an Ed25519
   request key; deployments whose enclaves support Ed25519 (or other)
   stable-key algorithms SHOULD document this explicitly.  The cnf.jwk
   request key algorithm is likewise enclave-determined.

   *Verification procedure:*

   1.   Parse the JWT without verifying the signature

   2.   Check the typ header (e.g., jkt-s256+jwt).  Reject if the type
        is not supported.

   3.   Determine the hash algorithm and iss prefix from the typ (e.g.,
        jkt-s256+jwt → SHA-256, urn:jkt:sha-256:)

   4.   Extract the jwk from the JWT header

   5.   Compute the JWK Thumbprint ([RFC7638]) of the header jwk using
        the determined hash algorithm

   6.   Construct the expected iss value by prepending the known prefix
        to the computed thumbprint

   7.   Verify the iss claim matches the constructed value by string
        equality

   8.   Verify the JWT signature using the header jwk

Hardt & Meunier          Expires 5 January 2027                [Page 11]
Internet-Draft               Signature-Keys                    July 2026

   9.   Validate exp and iat claims per policy

   10.  Extract the ephemeral public key from cnf.jwk

   11.  Verify the HTTP Message Signature using the ephemeral key

   *Use cases:*

   *  Devices with hardware-backed secure enclaves delegating to fast
      ephemeral keys

   *  Persistent pseudonymous identity without requiring registration or
      authority

   *  Mobile apps, laptops, and IoT devices with enclave-backed identity

3.5.  JWKS URI Discovery (jwks_uri)

   The jwks_uri scheme identifies the signer and enables key discovery
   via a metadata document containing a jwks_uri property.

   *Parameters:*

   *  id (REQUIRED, String) - Signer identifier (HTTPS URL)

   *  dwk (REQUIRED, String) - Dot well-known metadata document name
      under /.well-known/

   *  kid (REQUIRED, String) - Key identifier

   *Discovery procedure:*

   1.  Fetch {id}/.well-known/{dwk}

   2.  Parse as JSON metadata

   3.  Extract jwks_uri property

   4.  Fetch JWKS from jwks_uri

   5.  Find key with matching kid

   *Example:*

Signature-Key: sig=jwks_uri;id="https://client.example";dwk="example-configuration";kid="key-1"

   *Use cases:*

Hardt & Meunier          Expires 5 January 2027                [Page 12]
Internet-Draft               Signature-Keys                    July 2026

   *  Identified services with stable HTTPS identity

   *  Search engine crawlers and monitoring services

   *  Services requiring explicit entity identification

3.6.  JWT Confirmation Key (jwt)

   The jwt scheme embeds a public key inside a signed JWT using the cnf
   (confirmation) claim [RFC7800], enabling delegation and horizontal
   scale.

   *Parameters:*

   *  jwt (REQUIRED, String) - Compact-serialized JWT

   *JWT requirements:*

   *  MUST contain cnf.jwk claim with embedded JWK

   *  SHOULD contain iss claim (HTTPS URL of the issuer) — using SHOULD
      rather than MUST allows existing JWT infrastructure to be used
      without modification

   *  SHOULD contain dwk claim (dot well-known metadata document name) —
      the verifier constructs {iss}/.well-known/{dwk} to discover the
      issuer's jwks_uri.  Using SHOULD allows deployments where the
      verifier already knows the issuer's keys.

   *  SHOULD contain standard claims: sub, exp, iat

   *  Verifiers SHOULD verify the JWT typ header parameter has an
      expected value per deployment policy, to optimize for a quick
      rejection

   |  *Note:* The mechanism by which the JWT is obtained is out of scope
   |  of this specification.

   *Verification procedure:*

   1.  Parse the JWT parameter value per [RFC7519] Section 7.2.  Reject
       if the value is not a well-formed JWT.  This and subsequent pre-
       signature checks allow the verifier to fail early without
       expensive cryptographic operations or network fetches.

   2.  Verify the JWT typ header parameter has an expected value per
       policy.  Reject if unexpected.

Hardt & Meunier          Expires 5 January 2027                [Page 13]
Internet-Draft               Signature-Keys                    July 2026

   3.  Validate exp claim if present.  Reject if the token has expired.

   4.  Verify required claims are present (cnf.jwk, plus any claims
       required by deployment policy).  Reject if a required claim is
       missing.

   5.  If iss and dwk claims are present, fetch {iss}/.well-known/{dwk},
       parse as JSON metadata, extract jwks_uri.  Fetch JWKS from
       jwks_uri, find key matching kid in JWT header.  If iss or dwk is
       absent, the verifier MUST obtain the issuer's key through an
       application-specific mechanism.

   6.  Verify JWT signature using the discovered key

   7.  Validate remaining JWT claims per policy (iss, sub, etc.)

   8.  Extract JWK from cnf.jwk

   9.  Verify HTTP Message Signature using extracted key

   *Example:*

   Signature-Key: sig=jwt;jwt="eyJhbGciOiJFUzI1NiI..."

   *JWT payload example:*

   {
     "iss": "https://issuer.example",
     "dwk": "example-configuration",
     "sub": "instance-123",
     "exp": 1732210000,
     "cnf": {
       "jwk": {
         "kty": "OKP",
         "crv": "Ed25519",
         "x": "JrQLj5P_89iXES9-vFgrIy29clF9CC_oPPsw3c5D0bs"
       }
     }
   }

   *Use cases:*

   *  Distributed services with ephemeral instance keys

   *  Delegation scenarios where instances act on behalf of an authority

   *  Short-lived credentials for horizontal scaling

Hardt & Meunier          Expires 5 January 2027                [Page 14]
Internet-Draft               Signature-Keys                    July 2026

3.7.  Self-Issued JWT (self-jwt)

   The self-jwt scheme carries a signed JWT where the JWT issuer and the
   HTTP request signer are the same party.  The signing key is
   discoverable from the issuer's JWKS, and that same key verifies both
   the JWT and the HTTP Message Signature.  Unlike the jwt scheme, no
   cnf claim is present — the signing key is the confirmation key.

   *Parameters:*

   *  jwt (REQUIRED, String) - Compact-serialized JWT

   *JWT requirements:*

   *  MUST contain iss claim (HTTPS URL of the issuer)

   *  MUST contain dwk claim (dot well-known metadata document name) —
      the verifier constructs {iss}/.well-known/{dwk} to discover the
      issuer's jwks_uri

   *  MUST have kid in the JWT header identifying the signing key in the
      issuer's JWKS

   *  MUST NOT contain cnf claim

   *  SHOULD contain standard claims: sub, aud, exp, iat

   *  Verifiers SHOULD verify the JWT typ header parameter has an
      expected value per deployment policy, to optimize for a quick
      rejection

   |  *Note:* The mechanism by which the JWT is obtained is out of scope
   |  of this specification.

   *Verification procedure:*

   1.  Parse the JWT parameter value per [RFC7519] Section 7.2.
       Verifiers SHOULD reject if the value is not a well-formed JWT.
       This and subsequent pre-signature checks allow the verifier to
       fail early without expensive cryptographic operations or network
       fetches.

   2.  Verify the JWT typ header parameter has an expected value per
       policy.  Reject if unexpected.

   3.  Validate exp claim if present.  Reject if the token has expired.

Hardt & Meunier          Expires 5 January 2027                [Page 15]
Internet-Draft               Signature-Keys                    July 2026

   4.  Verify iss, dwk claims and kid JWT header parameter are present.
       Reject if any is absent.

   5.  Verify cnf claim is absent.  Reject if present.

   6.  Construct {iss}/.well-known/{dwk}, parse as JSON metadata,
       extract jwks_uri.  Fetch JWKS from jwks_uri, find the key
       matching kid from the JWT header.  Reject if the key is not found
       (error: unknown_key).

   7.  Verify JWT signature using the discovered key.

   8.  Validate remaining JWT claims per policy (sub, aud, etc.)

   9.  Verify HTTP Message Signature using the same key from step 6.

   *Example:*

Signature-Key: sig=self-jwt;jwt="eyJhbGciOiJFUzI1NiIsImtpZCI6InIxIn0..."

   JWT header:

   {
     "alg": "ES256",
     "kid": "r1",
     "typ": "aauth-resource+jwt"
   }

   JWT payload:

   {
     "iss": "https://resource.example",
     "dwk": "aauth-resource",
     "aud": "https://agent.example",
     "eid": "evt-abc123",
     "exp": 1732210000
   }

   The verifier fetches https://resource.example/.well-known/aauth-
   resource, retrieves the JWKS, finds the key with kid="r1", verifies
   the JWT signature with it, then uses that same key to verify the HTTP
   Message Signature.

   *Use cases:*

   *  Resources delivering events with application-layer claims that the
      verifier needs alongside key verification

Hardt & Meunier          Expires 5 January 2027                [Page 16]
Internet-Draft               Signature-Keys                    July 2026

   *  Clients presenting themselves directly without delegating to a
      separate authority

3.8.  X.509 Certificates (x509)

   The x509 scheme provides certificate-based verification using PKI
   trust chains.

   *Parameters:*

   *  x5u (REQUIRED, String) - URL to X.509 certificate chain (PEM
      format, [RFC7517] Section 4.6)

   *  x5t (REQUIRED, Byte Sequence) - Certificate thumbprint: SHA-256
      hash of DER-encoded end-entity certificate

   *Verification procedure:*

   1.  Check cache for certificate with matching x5t

   2.  If not cached or expired, fetch PEM from x5u

   3.  Validate certificate chain to trusted root CA

   4.  Check certificate validity and revocation status

   5.  Verify x5t matches end-entity certificate

   6.  Extract public key from end-entity certificate

   7.  Verify signature using extracted key

   8.  Cache certificate indexed by x5t

   *Example:*

Signature-Key: sig=x509;x5u="https://client.example/.well-known/cert.pem";x5t=:bWcoon4QTVn8Q6xiY0ekMD6L8bNLMkuDV2KtvsFc1nM=:

   *Use cases:*

   *  Enterprise environments with PKI infrastructure

   *  Integration with existing certificate management systems

   *  Scenarios requiring certificate revocation checking

   *  Regulated industries requiring certificate-based authentication

Hardt & Meunier          Expires 5 January 2027                [Page 17]
Internet-Draft               Signature-Keys                    July 2026

4.  Accept-Signature sigkey Parameter

   [RFC9421] Section 5 defines the Accept-Signature response header for
   requesting HTTP Message Signatures.  This document extends Accept-
   Signature with a sigkey parameter that indicates the type of
   Signature-Key the server requires.

4.1.  Parameter Definition

   The sigkey parameter is an Item parameter on each member of the
   Accept-Signature Dictionary.  Its value is a Token ([RFC8941],
   Section 3.3.4) with three defined values:

    +=======+=============================+==========================+
    | Value | Meaning                     | Acceptable Signature-Key |
    |       |                             | schemes                  |
    +=======+=============================+==========================+
    | jkt   | Pseudonymous key identified | hwk, jkt-jwt             |
    |       | by JWK Thumbprint           |                          |
    +-------+-----------------------------+--------------------------+
    | uri   | Key identified by a URI     | jwks_uri, jwt, self-jwt, |
    |       |                             | x509 (with URI SAN)      |
    +-------+-----------------------------+--------------------------+
    | x509  | Key from an X.509           | x509                     |
    |       | certificate chain           |                          |
    +-------+-----------------------------+--------------------------+

                                 Table 2

   These values represent ordered levels of identification.  A server
   requesting sigkey=uri accepts any scheme that provides a URI-based
   identifier.  A server requesting sigkey=x509 specifically requires
   PKI infrastructure.

   When sigkey is present, the keyid parameter ([RFC9421], Section 5)
   SHOULD NOT be included and MUST be ignored by the client.  Key
   identification is handled by the Signature-Key header schemes, not by
   keyid.  The algs and tag parameters remain applicable alongside
   sigkey.

4.2.  Label Binding

   The signature label in Accept-Signature ties together all four
   headers on the signed request.  When a server requests:

   Accept-Signature: sig1=("@method" "@path" "@authority");
       alg="ecdsa-p256-sha256";sigkey=uri

Hardt & Meunier          Expires 5 January 2027                [Page 18]
Internet-Draft               Signature-Keys                    July 2026

   The client responds with matching labels:

Signature-Key: sig1=jwks_uri;id="https://client.example";dwk="example-configuration";kid="key-1"
Signature-Input: sig1=("@method" "@path" "@authority" "signature-key");
    created=1732210000;keyid="https://client.example"
Signature: sig1=:MEQCIA5...:

   The signature-key covered component is added by the client per this
   specification's requirement that signature-key appear in covered
   components.  The server does not need to list it in Accept-Signature.

4.3.  Response Status Codes

   Accept-Signature with a sigkey parameter can be set for any response.
   Below is a list of what it MAY mean on responses with the following
   status codes:

   +========+================+==================+======================+
   | Status | Meaning        | Legacy client    | Signature-aware      |
   |        |                | behavior         | client behavior      |
   +========+================+==================+======================+
   | 401    | Authentication | Falls back to    | Signs request        |
   |        | required       | WWW-Authenticate | with appropriate     |
   |        |                |                  | Signature-Key        |
   |        |                |                  | scheme               |
   +--------+----------------+------------------+----------------------+
   | 402    | Payment +      | Processes        | Signs request        |
   |        | authentication | payment          | AND processes        |
   |        | required       | mechanism        | payment              |
   +--------+----------------+------------------+----------------------+
   | 429    | Rate limited   | Respects Retry-  | Signs request,       |
   |        |                | After, slows     | gets higher per-     |
   |        |                | down             | key rate limit       |
   +--------+----------------+------------------+----------------------+

                                  Table 3

   The 429 case is particularly important for incremental adoption: a
   server can add Accept-Signature with sigkey to its existing 429
   responses with zero risk.  Legacy clients ignore the unknown header
   and respect Retry-After.  Signature-aware clients sign with a
   pseudonymous key, giving the server a stable key thumbprint for per-
   client rate limiting — and the client gets a higher rate limit in
   return.

Hardt & Meunier          Expires 5 January 2027                [Page 19]
Internet-Draft               Signature-Keys                    July 2026

4.4.  sigkey Semantics

4.4.1.  jkt

   The server requires a signed request using a pseudonymous Signature-
   Key scheme (hwk or jkt-jwt).  The server can track the client by JWK
   Thumbprint ([RFC7638]) without knowing its identity.  This is useful
   for rate limiting anonymous requests, tracking repeat visitors by key
   thumbprint, spam prevention without requiring verified identity, and
   hardware-backed pseudonymous identity.

4.4.2.  uri

   The server requires a signed request with a URI-identified Signature-
   Key (jwks_uri, jwt, or x509 with a URI SAN).  This is useful for API
   access policies based on known clients, webhook signature
   verification, and allowlisting trusted clients for elevated rate
   limits.

4.4.3.  x509

   The server requires a signed request using an X.509 certificate chain
   (x509 scheme).  This is useful for enterprise environments with PKI
   infrastructure, regulated industries requiring certificate-based
   authentication, and scenarios requiring certificate revocation
   checking.

   [RFC9421] Section 5.2 defines the processing of Accept-Signature by
   the client.  If the sigkey parameter is unsupported, the client MAY
   ignore it.

   If a client already knows the server's sigkey requirement (from a
   previous interaction or metadata), it MAY sign the initial request
   directly without waiting for a challenge response.

4.5.  Incremental Adoption

   Accept-Signature with sigkey is designed for zero-coordination
   deployment.  The sigkey parameter is unknown to legacy clients and
   ignored per Structured Fields semantics — servers can add it to
   existing responses without breaking anything.

   *Stage 1 — Rate limiting (429):* A server adds Accept-Signature with
   sigkey=jkt to its 429 responses.  Legacy clients slow down as before.
   Signature-aware clients sign requests and get higher per-key rate
   limits.  The server gains per-client rate limiting without requiring
   registration or API keys.

Hardt & Meunier          Expires 5 January 2027                [Page 20]
Internet-Draft               Signature-Keys                    July 2026

   *Stage 2 — Authentication (401):* The server starts requiring
   signatures on some paths, returning 401 with Accept-Signature and
   sigkey=jkt.  It can include WWW-Authenticate alongside for legacy
   clients that have other auth mechanisms.  Signature-aware clients
   sign; legacy clients fall back to bearer tokens or other schemes.

   *Stage 3 — Identity (401):* The server upgrades from sigkey=jkt to
   sigkey=uri on sensitive paths, requiring verifiable client identity
   via jwks_uri, jwt, or x509 schemes.  The server can now make
   identity-based policy decisions without pre-registration.

   Each stage is independently deployable.  A server can use stage 1 on
   all endpoints while using stage 3 on admin endpoints.  No bilateral
   agreements or client coordination required.

4.6.  Coexistence with WWW-Authenticate

   Accept-Signature and WWW-Authenticate ([RFC9110], Section 11.6.1) are
   independent header fields; a response MAY include both.  A client
   that understands Signature-Key processes Accept-Signature with
   sigkey; a legacy client processes WWW-Authenticate.  Neither header's
   presence invalidates the other.

   HTTP/1.1 401 Unauthorized
   WWW-Authenticate: Bearer realm="api"
   Accept-Signature: sig1=("@method" "@path" "@authority");
       alg="ecdsa-p256-sha256";sigkey=uri

   A 402 response MAY include a payment mechanism such as x402 [x402] or
   the Micropayment Protocol ([I-D.ryan-httpauth-payment]) alongside
   Accept-Signature for authentication:

   HTTP/1.1 402 Payment Required
   WWW-Authenticate: Payment id="x7Tg2pLq", method="example",
       request="eyJhbW91bnQiOiIxMDAw..."
   Accept-Signature: sig1=("@method" "@path" "@authority");sigkey=jkt

4.7.  Examples

   Pseudonymous access:

   HTTP/1.1 401 Unauthorized
   Accept-Signature: sig1=("@method" "@path" "@authority");sigkey=jkt

   Identity with algorithm restriction:

Hardt & Meunier          Expires 5 January 2027                [Page 21]
Internet-Draft               Signature-Keys                    July 2026

   HTTP/1.1 401 Unauthorized
   Accept-Signature: sig1=("@method" "@authority" "@path");
       alg="ecdsa-p256-sha256";sigkey=uri

   Rate limiting with pseudonymous upgrade:

   HTTP/1.1 429 Too Many Requests
   Retry-After: 30
   Accept-Signature: sig1=("@method" "@path" "@authority");sigkey=jkt

   Payment with pseudonymous authentication:

   HTTP/1.1 402 Payment Required
   WWW-Authenticate: Payment id="x7Tg2pLq", method="example",
       request="eyJhbW91bnQiOiIxMDAw..."
   Accept-Signature: sig1=("@method" "@path" "@authority");sigkey=jkt

4.8.  Client Processing

   When a client receives a response containing an Accept-Signature
   header with a sigkey parameter, it MAY retry the request with an HTTP
   Message Signature using a Signature-Key scheme appropriate for the
   indicated sigkey value.

   When a 429 response includes both Retry-After and Accept-Signature
   with sigkey, the client MAY retry one time with a signed request
   without waiting for the Retry-After interval.  Signing the request
   provides a key thumbprint that enables per-client rate limiting,
   which may result in a higher rate limit for the client.

   A server MAY return a 429 response without Accept-Signature to a
   signed request when it wants to rate-limit the client regardless of
   signing.  In this case, the client MUST respect Retry-After as usual.

   |  *Open Issue:* Should this specification define a baseline HTTP
   |  Message Signatures profile (minimum covered components, timestamp
   |  requirements, verification steps), or is that always the
   |  responsibility of the protocol using these headers?  See GitHub
   |  issue #7 (https://github.com/dickhardt/signature-key/issues/7).

5.  Signature-Error HTTP Response Header

   When a server rejects a signed request due to a signature-related
   error, the response SHOULD include the Signature-Error header.  The
   response status code is typically 400 Bad Request, since the
   signature or keying material is malformed or invalid.  A server MAY
   use 401 Unauthorized for recoverable errors (e.g.,
   unsupported_algorithm, invalid_input) where the client can retry with

Hardt & Meunier          Expires 5 January 2027                [Page 22]
Internet-Draft               Signature-Keys                    July 2026

   corrected parameters.

5.1.  Header Structure

   The Signature-Error header is a Dictionary ([RFC8941], Section 3.2)
   with the following member:

   *  error (REQUIRED): A Token ([RFC8941], Section 3.3.4) indicating
      the error code.

   Additional members are defined per error code.  Recipients MUST
   ignore unknown members.

   Signature-Error: error=unsupported_algorithm,
       supported_algorithms=("ed25519" "ecdsa-p256-sha256")

   The Signature-Error header is the authoritative source for machine-
   readable error information.  The client MUST NOT depend on the
   response body for error handling.

5.2.  Response Body

   Servers SHOULD use Problem Details [RFC9457] (application/
   problem+json) for the response body when returning Signature-Error.
   The type member SHOULD be a URN of the form urn:ietf:params:sig-
   error:<error-code>, where <error-code> matches the error value in the
   header.

   {
     "type": "urn:ietf:params:sig-error:unsupported_algorithm",
     "title": "Unsupported signature algorithm",
     "status": 400,
     "detail": "The server does not support rsa-v1_5-sha256"
   }

   Extension members in the Problem Details object (e.g.,
   supported_algorithms) MAY duplicate information from the Signature-
   Error header for convenience.  When the header and body conflict, the
   header takes precedence.

5.3.  Access Denied

   When the server successfully verifies the client's signature and
   identity but denies access based on policy (e.g., the client is not
   authorized for this resource), the server returns 403 Forbidden.
   This is not a signature error — the authentication succeeded but
   authorization was denied.  The response MUST NOT include an Accept-
   Signature header with sigkey or a Signature-Error header.

Hardt & Meunier          Expires 5 January 2027                [Page 23]
Internet-Draft               Signature-Keys                    July 2026

5.4.  Error Codes

5.4.1.  unsupported_algorithm

   The signing algorithm used by the client is not supported by the
   server.

   *  supported_algorithms (REQUIRED): An Inner List of String
      ([RFC8941], Section 3.1.1) listing the algorithms the server
      accepts, using identifiers from the HTTP Signature Algorithms
      registry ([RFC9421], Section 6.2).  The registry description for
      each identifier specifies the corresponding key type and curve.
      The response MUST include this member.

   Signature-Error: error=unsupported_algorithm,
       supported_algorithms=("ed25519" "ecdsa-p256-sha256")

5.4.2.  invalid_signature

   The HTTP Message Signature is missing, malformed, or cryptographic
   verification failed.  This includes missing Signature, Signature-
   Input, or Signature-Key headers, an expired created timestamp, or a
   signature that does not verify.

   Signature-Error: error=invalid_signature

5.4.3.  invalid_input

   The Signature-Input is missing required covered components.

   *  required_input (OPTIONAL): An Inner List of String ([RFC8941],
      Section 3.1.1) listing the covered components the server requires.
      The response SHOULD include this member.

   Signature-Error: error=invalid_input,
       required_input=("@method" "@authority" "@path"
       "signature-key" "content-digest")

5.4.4.  invalid_request

   The request is malformed or missing required information unrelated to
   signature verification — such as missing query parameters or an
   unsupported content type.

   Signature-Error: error=invalid_request

Hardt & Meunier          Expires 5 January 2027                [Page 24]
Internet-Draft               Signature-Keys                    July 2026

5.4.5.  invalid_key

   The public key in Signature-Key could not be parsed, is expired, or
   does not meet the server's trust requirements.

   Signature-Error: error=invalid_key

5.4.6.  unknown_key

   The public key from Signature-Key does not match any key at the
   client's jwks_uri (applicable when the client uses scheme=jwks_uri).
   The server SHOULD re-fetch the JWKS once before returning this error,
   to handle key rotation.

   Signature-Error: error=unknown_key

5.4.7.  invalid_jwt

   The JWT in the Signature-Key header (when using scheme=jwt or
   scheme=jkt-jwt) is malformed or its signature verification failed.

   Signature-Error: error=invalid_jwt

5.4.8.  expired_jwt

   The JWT in the Signature-Key header (when using scheme=jwt or
   scheme=jkt-jwt) has expired (exp claim is in the past).

   Signature-Error: error=expired_jwt

6.  Security Considerations

6.1.  Key Validation

   Verifiers MUST validate all cryptographic material before use:

   *  *hwk*: Validate JWK structure and key parameters per [RFC7517]

   *  *jwks_uri*: Verify HTTPS transport and validate fetched JWKS per
      [RFC7517]

   *  *x509*: Validate complete certificate chain per [RFC5280], check
      revocation status

   *  *jwt*: Verify JWT signature per [RFC7519] and validate embedded
      JWK per [RFC7517]

Hardt & Meunier          Expires 5 January 2027                [Page 25]
Internet-Draft               Signature-Keys                    July 2026

   *  *self-jwt*: Verify JWT signature per [RFC7519] using the key
      discovered from {iss}/.well-known/{dwk}; reuse that key as the
      HTTP signing key

   *  *jkt-jwt*: Verify JWT signature per [RFC7519] using header jwk,
      validate thumbprint matches iss per [RFC7638], validate embedded
      ephemeral JWK per [RFC7517]

6.2.  Caching and Performance

   Verifiers MAY cache keys to improve performance but MUST implement
   appropriate cache expiration:

   *  *jwks_uri*: Respect cache-control headers, implement reasonable
      TTLs.  Verifiers MUST NOT refetch a given issuer's JWKS more
      frequently than once per minute to prevent abuse.

   *  *x509*: Cache by x5t, invalidate on certificate expiry

   *  *jwt*: Cache embedded keys until JWT expiration

   *  *self-jwt*: Cache discovered keys until JWT expiration; cache by
      iss + kid

   *  *jkt-jwt*: Cache embedded keys until JWT expiration; cache by iss
      thumbprint URI

   Verifiers SHOULD implement cache limits to prevent resource
   exhaustion attacks.

   When the Signature-Key scheme is jwks_uri and a cached key matching
   the JWT kid fails signature verification, the verifier SHOULD refresh
   the issuer's JWKS once and retry verification before returning
   unknown_key (if the key is then absent) or invalid_jwt (if
   verification still fails), subject to the once-per-minute fetch floor
   and egress admission (§Scheme-Specific Risks) that apply to unknown-
   kid refreshes.  This covers silent re-keying where the issuer
   replaces key material under the same kid without changing the
   identifier.

6.3.  Scheme-Specific Risks

   *hwk*: No identity verification - suitable only for scenarios where
   pseudonymous access is acceptable.

   *jkt-jwt*: The security of this scheme depends on the enclave key's
   private key remaining protected in hardware.  If the enclave key is
   compromised, all delegated ephemeral keys are compromised.  Verifiers

Hardt & Meunier          Expires 5 January 2027                [Page 26]
Internet-Draft               Signature-Keys                    July 2026

   should be aware that the jkt-jwt scheme implies but does not prove
   hardware protection — there is no attestation mechanism in this
   scheme.  Unlike the jwt scheme where trust is rooted in a
   discoverable issuer, jkt-jwt trust is rooted in the key itself.
   Verifiers MUST understand that any party can create a jkt-jwt — the
   scheme provides pseudonymous identity, not verified identity.  The
   exp claim on the JWT controls how long the ephemeral key is valid.
   Shorter lifetimes limit the exposure window if an ephemeral key is
   compromised.  Implementations SHOULD use the shortest practical
   lifetime.  The iss value is a JWK Thumbprint URI — a globally unique,
   collision-resistant identifier.  The verifier MUST always compute the
   expected iss from the header jwk and compare by string equality —
   never trust the iss value alone.

   *jwks_uri*: Relies on HTTPS security — vulnerable to DNS/CA
   compromise.  Beyond HTTPS validation, nothing prevents an attacker
   from copying a client's public keys and serving them from a different
   domain.  Verifiers SHOULD verify that the id parameter in the
   Signature-Key header matches an expected or authorized origin.

   Because the jwks_uri (and the metadata document that yields it) is
   controlled by the asserted signer, an unconstrained verifier can be
   induced to fetch attacker-chosen internal URLs (SSRF).  Verifiers
   MUST apply egress admission before fetching issuer metadata or a
   jwks_uri:

   *  Require HTTPS for all outbound fetches.
   *  Enforce response-size and timeout limits.
   *  Refuse or constrain redirects (at minimum, do not follow redirects
      to a different host).
   *  Reject private, loopback, and link-local destination addresses
      unless explicitly allowed by deployment configuration.
   *  Defend against DNS rebinding by pinning the resolved IP address
      for the duration of the connection.
   *  Treat cross-origin jwks_uri URLs (where the JWKS host differs from
      the metadata host) as requiring explicit deployment admission.

   *jwt*: Delegation trust depends on JWT issuer verification.
   Verifiers MUST validate JWT signatures and claims before trusting
   embedded keys.

Hardt & Meunier          Expires 5 January 2027                [Page 27]
Internet-Draft               Signature-Keys                    July 2026

   *self-jwt*: Trust is rooted entirely in the issuer's JWKS.  The same
   SSRF egress admission requirements that apply to jwks_uri and jwt
   apply here — the iss and dwk values are asserted by the presenter.
   Verifiers MUST validate that cnf is absent before treating the scheme
   as self-issued; a JWT containing cnf MUST be rejected.  Short JWT
   lifetimes are especially important because the signing key also
   authenticates the HTTP request — compromise of the key is immediately
   exploitable at both layers.

   *x509*: Requires robust certificate validation including revocation
   checking.  Verifiers MUST NOT skip certificate chain validation.

6.4.  Algorithm Selection

   The signature algorithm is determined by the key material in
   Signature-Key, not by the optional alg parameter in Signature-Input
   ([RFC9421], Section 2.3).  For JWK-based schemes (hwk, jkt-jwt,
   jwks_uri, jwt, self-jwt), the algorithm is identified by the key type
   and curve (kty + crv) or by the alg parameter in the JWK ([RFC7517]).
   For the x509 scheme, the algorithm is determined by the certificate's
   public key type.

   If the alg parameter is present in Signature-Input, verifiers MUST
   verify it is consistent with the key material.  If it is absent,
   verifiers derive the algorithm from the key.

   Verifiers MUST:

   *  Validate the algorithm against policy (reject weak algorithms)

   *  Ensure the key type is consistent with the derived algorithm

   *  Reject keys whose type does not match an acceptable algorithm

6.5.  Signature-Key Integrity

   The Signature-Key header SHOULD be included as a covered component in
   Signature-Input:

Signature-Input: sig=("@method" "@authority" "@path" "signature-key"); created=1732210000

   If signature-key is not covered, an attacker can modify the header
   without invalidating the signature.  Attacks include:

   *Scheme substitution*: An attacker extracts the public key from an
   hwk scheme and republishes it via jwks_uri under their own identity,
   causing verifiers to attribute the request to the attacker.

Hardt & Meunier          Expires 5 January 2027                [Page 28]
Internet-Draft               Signature-Keys                    July 2026

   *Identity substitution*: An attacker modifies the id parameter in a
   jwks_uri scheme to point to their own metadata endpoint that returns
   the same public key, impersonating a different signer.

   Verifiers SHOULD reject requests where signature-key is not a covered
   component.

7.  Privacy Considerations

7.1.  Pseudonymity vs. Identity

   The hwk and jkt-jwt schemes enable pseudonymous operation where the
   signer's identity is not disclosed.  Verifiers should be aware that:

   *  A server can track a client across requests by JWK Thumbprint
      ([RFC7638]).  If a client uses the same key across multiple
      servers, those servers could correlate the client's activity.
      Clients MUST use distinct keys for distinct servers to prevent
      cross-server correlation of pseudonymous identity.

   *  The jkt-jwt thumbprint is stable across sessions (tied to the
      enclave key), enabling long-term tracking even when ephemeral keys
      rotate.

   *  Verifiers should not log or retain pseudonymous keys beyond
      operational necessity.

   The jwks_uri, x509, jwt, and self-jwt schemes reveal signer identity.
   When a client presents its identity via these schemes, the server
   learns the client's HTTPS URL or certificate subject, revealing which
   software is making the request.  Servers SHOULD NOT disclose client
   identity information to third parties without the client operator's
   consent.

7.2.  Key Discovery Tracking

   The jwks_uri, jwt, self-jwt, and x509 schemes require verifiers to
   fetch resources from signer-controlled URLs.  This creates tracking
   vectors:

   *  Signers can observe when and from where keys are fetched.  In
      particular, when a server fetches a client's JWKS from jwks_uri at
      verification time, the fetch reveals to the JWKS host that someone
      is verifying signatures for that client.

   *  Verifiers should cache keys to minimize fetches.

Hardt & Meunier          Expires 5 January 2027                [Page 29]
Internet-Draft               Signature-Keys                    July 2026

   *  Verifiers may wish to use shared caching infrastructure to reduce
      fingerprinting.

7.3.  JWT Contents

   JWTs in the jwt scheme may contain additional claims beyond cnf.
   Verifiers should:

   *  Only process claims necessary for verification

   *  Not log or retain unnecessary JWT claims

   *  Be aware that JWT contents are visible to network observers unless
      using TLS

8.  IANA Considerations

8.1.  HTTP Field Name Registration

   This document registers the following header fields in the "Hypertext
   Transfer Protocol (HTTP) Field Name Registry" defined in [RFC9110].

   Header field name: Signature-Key

   Applicable protocol: http

   Status: standard

   Author/Change controller: IETF

   Specification document(s): [this document]

   Header field name: Signature-Error

   Applicable protocol: http

   Status: standard

   Author/Change controller: IETF

   Specification document(s): [this document]

8.2.  Signature-Key Scheme Registry

   This document establishes the "HTTP Signature-Key Scheme" registry.
   This registry allows for the definition of additional key
   distribution schemes beyond those defined in this document.

Hardt & Meunier          Expires 5 January 2027                [Page 30]
Internet-Draft               Signature-Keys                    July 2026

8.2.1.  Registration Procedure

   New scheme registrations require Specification Required per
   [RFC8126].

8.2.2.  Initial Registry Contents

    +==========+====================================+=================+
    | Scheme   | Description                        | Reference       |
    +==========+====================================+=================+
    | hwk      | Header Web Key - inline public key | [this document] |
    +----------+------------------------------------+-----------------+
    | jkt-jwt  | JKT JWT Self-Issued Key Delegation | [this document] |
    |          | - enclave-backed delegation        |                 |
    +----------+------------------------------------+-----------------+
    | jwks_uri | JWKS URI Discovery - key discovery | [this document] |
    |          | via metadata                       |                 |
    +----------+------------------------------------+-----------------+
    | jwt      | JWT Confirmation Key - delegated   | [this document] |
    |          | key in JWT                         |                 |
    +----------+------------------------------------+-----------------+
    | self-jwt | Self-Issued JWT - signer and       | [this document] |
    |          | issuer are the same party          |                 |
    +----------+------------------------------------+-----------------+
    | x509     | X.509 Certificate - PKI            | [this document] |
    |          | certificate chain                  |                 |
    +----------+------------------------------------+-----------------+

                                  Table 4

8.2.3.  Registration Template

   Scheme Name:  The token value used in the Signature-Key header
   Description:  A brief description of the scheme
   Specification:  Reference to the specification defining the scheme
   Parameters:  List of parameters defined for this scheme

8.3.  HTTP Signature Metadata Parameters

   This document registers the following parameter in the "HTTP
   Signature Metadata Parameters" registry established by [RFC9421],
   Section 6.3.

   Parameter Name: sigkey

   Status: standard

   Specification document(s): [this document]

Hardt & Meunier          Expires 5 January 2027                [Page 31]
Internet-Draft               Signature-Keys                    July 2026

   Description: Indicates the type of Signature-Key the server requires.
   Defined values: jkt (pseudonymous key identified by JWK Thumbprint),
   uri (key identified by a URI), x509 (X.509 certificate chain).

8.4.  URN Sub-namespace Registration

   This document registers the following URN sub-namespace in the "IETF
   URN Sub-namespace for Registered Protocol Parameter Identifiers"
   registry defined in [RFC3553].

   Registry name: sig-error

   Specification: [this document]

   Repository: [this document], Section on Error Codes

   Index value: Values are registered in the "Signature Error Code"
   registry defined in this document.

   The URN pattern is urn:ietf:params:sig-error:<error-code>, where
   <error-code> corresponds to a value in the Signature Error Code
   registry.  These URNs are used as Problem Details type values
   ([RFC9457]) in response bodies accompanying Signature-Error headers.

8.5.  Signature Error Code Registry

   This document establishes the "Signature Error Code" registry.  New
   values may be registered following the Specification Required policy
   ([RFC8126]).

8.5.1.  Initial Registry Contents

   +=======================+===============================+===========+
   | Value                 | Description                   | Reference |
   +=======================+===============================+===========+
   | unsupported_algorithm | Signing algorithm             | [this     |
   |                       | not supported                 | document] |
   +-----------------------+-------------------------------+-----------+
   | invalid_signature     | Signature missing,            | [this     |
   |                       | malformed, or                 | document] |
   |                       | verification failed           |           |
   +-----------------------+-------------------------------+-----------+
   | invalid_input         | Missing required              | [this     |
   |                       | covered components            | document] |
   +-----------------------+-------------------------------+-----------+
   | invalid_request       | Missing required              | [this     |
   |                       | info unrelated to             | document] |
   |                       | signature                     |           |

Hardt & Meunier          Expires 5 January 2027                [Page 32]
Internet-Draft               Signature-Keys                    July 2026

   +-----------------------+-------------------------------+-----------+
   | invalid_key           | Key cannot be parsed          | [this     |
   |                       | or doesn't meet               | document] |
   |                       | trust requirements            |           |
   +-----------------------+-------------------------------+-----------+
   | unknown_key           | Key not found at              | [this     |
   |                       | jwks_uri                      | document] |
   +-----------------------+-------------------------------+-----------+
   | invalid_jwt           | JWT malformed or              | [this     |
   |                       | signature                     | document] |
   |                       | verification failed           |           |
   +-----------------------+-------------------------------+-----------+
   | expired_jwt           | JWT expired                   | [this     |
   |                       |                               | document] |
   +-----------------------+-------------------------------+-----------+

                                  Table 5

9.  Document History

   _Note: This section is to be removed before publishing as an RFC._

   *  draft-hardt-httpbis-signature-key-06

      -  Added self-jwt as a new standalone scheme for self-issued JWTs
         where the signer and JWT issuer are the same party.  The JWT
         signing key (discovered via {iss}/.well-known/{dwk}) is reused
         as the HTTP signing key; no cnf claim is present.

   *  draft-hardt-httpbis-signature-key-05

      -  Incorporated implementer feedback from Joshua Gay (sidecat).
      -  SSRF / egress admission: extended the jwks_uri risk bullet with
         a mandatory egress-admission checklist covering HTTPS, size/
         timeout limits, redirect policy, private/loopback address
         rejection, DNS rebinding defense, and cross-origin JWKS
         admission.
      -  Caching: added once-per-minute fetch floor to the jwks_uri
         cache bullet; added same-kid signature-failure refresh rule —
         one JWKS refresh and retry before returning unknown_key or
         invalid_jwt, subject to the same floor and egress-admission
         policy as unknown-kid refreshes.
      -  jkt-jwt: added algorithm note after the worked example — the
         stable (enclave) key algorithm is enclave-determined;
         deployments supporting Ed25519 or other stable-key algorithms
         SHOULD document this explicitly.
      -  Added Joshua Gay to acknowledgments.

Hardt & Meunier          Expires 5 January 2027                [Page 33]
Internet-Draft               Signature-Keys                    July 2026

   *  draft-hardt-httpbis-signature-key-04

      -  Renamed spec from "HTTP Signature-Key Header" to "HTTP
         Signature Keys"
      -  Added sigkey parameter for Accept-Signature (RFC 9421
         Section 5) with three values: jkt (pseudonymous), uri (URI-
         identified), x509 (PKI certificate)
      -  Added Signature-Error response header for structured signature
         verification error responses
      -  Added incremental adoption section describing zero-coordination
         deployment via 429/401/402 status codes
      -  Added privacy considerations for key thumbprint tracking, agent
         identity disclosure, and JWKS fetch side channel
      -  Registered sigkey in the HTTP Signature Metadata Parameters
         registry (RFC 9421 Section 6.3)
      -  Established Signature Error Code Registry

   *  draft-hardt-httpbis-signature-key-03

      -  Added jkt-jwt scheme for self-issued key delegation
      -  Renamed well-known parameter to dwk (dot well-known)
      -  Added iss and dwk claims to jwt scheme (SHOULD) for issuer key
         discovery
      -  Added early validation step to jwt verification procedure
         (format, typ, exp checks before network fetches)
      -  Added TOFU reference (RFC 7435) to jkt-jwt scheme
      -  Added design rationale for jwks_uri vs inline JWKS
      -  Moved hwk string vs byte sequence design note to rationale
         appendix
      -  Reordered schemes
      -  Added acknowledgments

   *  draft-hardt-httpbis-signature-key-02

      -  Changed x5t parameter to byte sequence per reviewer feedback
      -  Added structured field types to all parameters
      -  Added design note explaining string vs byte sequence choice for
         hwk

   *  draft-hardt-httpbis-signature-key-01

      -  Initial public draft with four schemes: hwk, jwks_uri, x509,
         jwt

10.  Acknowledgments

   The author would like to thank Joshua Gay and Yaron Sheffer for their
   feedback on this specification.

Hardt & Meunier          Expires 5 January 2027                [Page 34]
Internet-Draft               Signature-Keys                    July 2026

11.  References

11.1.  Normative References

   [RFC3553]  Mealling, M., Masinter, L., Hardie, T., and G. Klyne, "An
              IETF URN Sub-namespace for Registered Protocol
              Parameters", BCP 73, RFC 3553, DOI 10.17487/RFC3553, June
              2003, <https://www.rfc-editor.org/info/rfc3553>.

   [RFC5280]  Cooper, D., Santesson, S., Farrell, S., Boeyen, S.,
              Housley, R., and W. Polk, "Internet X.509 Public Key
              Infrastructure Certificate and Certificate Revocation List
              (CRL) Profile", RFC 5280, DOI 10.17487/RFC5280, May 2008,
              <https://www.rfc-editor.org/info/rfc5280>.

   [RFC7517]  Jones, M., "JSON Web Key (JWK)", RFC 7517,
              DOI 10.17487/RFC7517, May 2015,
              <https://www.rfc-editor.org/info/rfc7517>.

   [RFC7519]  Jones, M., Bradley, J., and N. Sakimura, "JSON Web Token
              (JWT)", RFC 7519, DOI 10.17487/RFC7519, May 2015,
              <https://www.rfc-editor.org/info/rfc7519>.

   [RFC7638]  Jones, M. and N. Sakimura, "JSON Web Key (JWK)
              Thumbprint", RFC 7638, DOI 10.17487/RFC7638, September
              2015, <https://www.rfc-editor.org/info/rfc7638>.

   [RFC7800]  Jones, M., Bradley, J., and H. Tschofenig, "Proof-of-
              Possession Key Semantics for JSON Web Tokens (JWTs)",
              RFC 7800, DOI 10.17487/RFC7800, April 2016,
              <https://www.rfc-editor.org/info/rfc7800>.

   [RFC8126]  Cotton, M., Leiba, B., and T. Narten, "Guidelines for
              Writing an IANA Considerations Section in RFCs", BCP 26,
              RFC 8126, DOI 10.17487/RFC8126, June 2017,
              <https://www.rfc-editor.org/info/rfc8126>.

   [RFC8941]  Nottingham, M. and P. Kamp, "Structured Field Values for
              HTTP", RFC 8941, DOI 10.17487/RFC8941, February 2021,
              <https://www.rfc-editor.org/info/rfc8941>.

   [RFC9110]  Fielding, R., Ed., Nottingham, M., Ed., and J. Reschke,
              Ed., "HTTP Semantics", STD 97, RFC 9110,
              DOI 10.17487/RFC9110, June 2022,
              <https://www.rfc-editor.org/info/rfc9110>.

Hardt & Meunier          Expires 5 January 2027                [Page 35]
Internet-Draft               Signature-Keys                    July 2026

   [RFC9421]  Backman, A., Ed., Richer, J., Ed., and M. Sporny, "HTTP
              Message Signatures", RFC 9421, DOI 10.17487/RFC9421,
              February 2024, <https://www.rfc-editor.org/info/rfc9421>.

   [RFC9457]  Nottingham, M., Wilde, E., and S. Dalal, "Problem Details
              for HTTP APIs", RFC 9457, DOI 10.17487/RFC9457, July 2023,
              <https://www.rfc-editor.org/info/rfc9457>.

11.2.  Informative References

   [I-D.hardt-email-verification]
              Hardt, D. and S. Goto, "Email Verification Protocol", Work
              in Progress, Internet-Draft, draft-hardt-email-
              verification-00, 17 June 2026,
              <https://datatracker.ietf.org/doc/html/draft-hardt-email-
              verification-00>.

   [I-D.hardt-oauth-aauth-protocol]
              Hardt, D., "AAuth Protocol", Work in Progress, Internet-
              Draft, draft-hardt-oauth-aauth-protocol-08, 24 June 2026,
              <https://datatracker.ietf.org/doc/html/draft-hardt-oauth-
              aauth-protocol-08>.

   [I-D.ryan-httpauth-payment]
              Ryan, B., Moxey, J., Meagher, T., Weinstein, J., and S.
              Kaliski, "The "Payment" HTTP Authentication Scheme", Work
              in Progress, Internet-Draft, draft-ryan-httpauth-payment-
              01, 17 March 2026, <https://datatracker.ietf.org/doc/html/
              draft-ryan-httpauth-payment-01>.

   [OpenID.Discovery]
              Sakimura, N., Bradley, J., Jones, M., and E. Jay, "OpenID
              Connect Discovery 1.0", November 2014,
              <https://openid.net/specs/openid-connect-discovery-
              1_0.html>.

   [RFC7435]  Dukhovni, V., "Opportunistic Security: Some Protection
              Most of the Time", RFC 7435, DOI 10.17487/RFC7435,
              December 2014, <https://www.rfc-editor.org/info/rfc7435>.

   [RFC8414]  Jones, M., Sakimura, N., and J. Bradley, "OAuth 2.0
              Authorization Server Metadata", RFC 8414,
              DOI 10.17487/RFC8414, June 2018,
              <https://www.rfc-editor.org/info/rfc8414>.

   [x402]     x402 Foundation, "x402: HTTP 402 Payment Protocol", 2025,
              <https://docs.x402.org>.

Hardt & Meunier          Expires 5 January 2027                [Page 36]
Internet-Draft               Signature-Keys                    July 2026

Appendix A.  Design Rationale

A.1.  Why jwks_uri Instead of Inline JWKS?

   The jwks_uri and jwt schemes reference a jwks_uri property in the
   .well-known metadata document rather than embedding the JWKS directly
   in the metadata.  This separation of concerns is deliberate:

   1.  *Independent key rotation*: Keys can be rotated by updating the
       JWKS endpoint without modifying the .well-known metadata
       document.  This decouples key lifecycle management from
       configuration management, allowing operations teams to rotate
       keys on their own schedule without redeploying metadata.

   2.  *Independent management*: The .well-known metadata document and
       the JWKS can be hosted, managed, and secured by different systems
       or teams.  For example, an identity team may manage keys while a
       platform team manages service metadata.

   3.  *Caching semantics*: The JWKS endpoint can have its own cache-
       control headers tuned for key rotation frequency (e.g., short
       TTLs during a rotation event), independent of the .well-known
       document's caching policy.

   4.  *Consistency with existing standards*: This approach mirrors the
       pattern established by OpenID Connect Discovery
       [OpenID.Discovery] and OAuth Authorization Server Metadata
       [RFC8414], which both use jwks_uri in metadata documents for the
       same reasons.

A.2.  Why a Separate Header?

   An alternative design would extend Signature-Input with additional
   parameters to carry key material.  This was considered and rejected
   for several reasons:

   1.  *Parameter complexity*: Each scheme has a different set of
       parameters (e.g., hwk needs kty, crv, x, y; jwks_uri needs id,
       dwk, kid; jwt needs a full JWT string).  Overloading Signature-
       Input with all possible key parameters across all schemes would
       make the Signature-Input grammar unwieldy and harder to parse.

   2.  *Separation of concerns*: Signature-Input describes _what_ is
       signed and _how_ (covered components, algorithm, timestamps).
       Signature-Key describes _who_ signed it and _where to find the
       key_. These are distinct concerns, and separating them into
       distinct headers makes each easier to understand and process
       independently.

Hardt & Meunier          Expires 5 January 2027                [Page 37]
Internet-Draft               Signature-Keys                    July 2026

   3.  *Extensibility*: A separate header with a scheme registry allows
       new key distribution mechanisms to be added without modifying the
       Signature-Input grammar.  New schemes can define arbitrary
       parameters without coordination with RFC 9421.

   4.  *Multiple signatures*: With a dictionary structure keyed by
       label, each signature can use a different scheme.  This is
       natural in a separate header but would create complex nesting if
       embedded in Signature-Input.

A.3.  Why Schemes Instead of Just a Key and Key ID?

   A simpler design would define Signature-Key as carrying only a public
   key (or key reference) and a key identifier, without the scheme
   abstraction.  This was considered insufficient because:

   1.  *Trust model varies*: A bare key tells the verifier nothing about
       the trust model.  Is this a pseudonymous key to be evaluated on
       its own merits (hwk)?  A key bound to a discoverable identity
       (jwks_uri)?  A delegated key from an authority (jwt)?  A
       certificate-backed key (x509)?  The scheme token tells the
       verifier which verification procedure to follow and what trust
       properties the key carries.

   2.  *Verification procedure differs*: Each scheme has a fundamentally
       different verification path. hwk requires no external fetches.
       jwks_uri requires metadata discovery. x509 requires certificate
       chain validation. jwt requires JWT signature verification before
       the HTTP signature can be verified.  A key-and-ID-only design
       would push scheme detection to heuristics or out-of-band
       agreement.

   3.  *Security properties differ*: Without an explicit scheme, a
       verifier cannot distinguish between a self-asserted key and a CA-
       certified key.  The scheme makes the trust model explicit,
       allowing verifiers to enforce policy (e.g., "only accept jwt or
       x509 schemes").

   4.  *Interoperability*: Explicit schemes create clear
       interoperability targets.  Two implementations that support the
       jwt scheme know exactly what to expect from each other.  Without
       schemes, the same key material could be interpreted differently
       by different implementations.

Hardt & Meunier          Expires 5 January 2027                [Page 38]
Internet-Draft               Signature-Keys                    July 2026

A.4.  Why Strings Instead of Byte Sequences for hwk?

   The hwk parameters use structured field strings rather than byte
   sequences.  JWK key values are base64url-encoded per [RFC7517], while
   structured field byte sequences use base64 encoding per [RFC8941].
   Using strings allows implementations to pass JWK values directly
   without converting between base64url and base64, avoiding a potential
   source of encoding bugs.

Authors' Addresses

   Dick Hardt
   Hellō
   Email: dick.hardt@gmail.com

   Thibault Meunier
   Cloudflare
   Email: ot-ietf@thibault.uk

Hardt & Meunier          Expires 5 January 2027                [Page 39]