--- eip: 8128 title: Signed HTTP Requests with Ethereum description: Authenticate HTTP requests using HTTP Message Signatures with Ethereum accounts author: Domenico Macellaro (@zerohex-eth) , Jacopo Ranalli (@jacopo-eth) discussions-to: https://ethereum-magicians.org/t/erc-8128-signed-http-requests-with-ethereum/27515 status: Draft type: Standards Track category: ERC created: 2026-01-16 requires: 155, 191, 1271, 6492, 7702 --- ## Abstract A standard to authenticate HTTP requests with Ethereum accounts using HTTP Message Signatures. ## Motivation HTTP APIs are commonly authenticated using bearer credentials (cookies, API keys, JWTs). Possession of these credentials authenticates the caller but does not itself bind authorization to a particular HTTP request. HTTP message signatures improve this by binding a cryptographic proof to the HTTP request itself: the client signs selected request components so the server can verify request integrity and authorization without issuing or storing bearer credentials. Sign-In with Ethereum ([ERC-4361](./eip-4361.md)) provides a widely adopted pattern for authenticating Ethereum accounts in interactive frontends. This proposal extends Ethereum-based authentication to generic HTTP traffic (e.g. API clients, servers, and agents) without bespoke sign-up flows, session issuance, or long-lived bearer credentials. As agentic workflows and crypto-native applications increasingly interact through APIs, a standard way to authenticate and authorize requests becomes necessary. Ethereum accounts provide a stateful, globally verifiable identity. Using them as the signing authority for HTTP message signatures allows requests to be authorized by proving control of an address (Externally Owned Account) or by satisfying a contract-defined policy (Smart Contract Account via [ERC-1271](./eip-1271.md)). Account provisioning, custody, and recovery remain the responsibility of wallet infrastructure. The same Account can identify a user or agent across HTTP services and separately authorized onchain operations; request authentication does not itself authorize spending. The proposal standardizes Ethereum-based authentication for HTTP requests, aligned with the [HTTP Message Signatures](https://www.rfc-editor.org/rfc/rfc9421) model where practical. Traditional authentication systems place security policy primarily on the server: the server issues credentials, defines scopes, and enforces risk centrally. The specification intentionally inverts that model. The signer chooses the cryptographic guarantees attached to each request by selecting which request components to bind and whether to enable replay protection. The verifier evaluates those guarantees against its acceptance rules, but does not impose a single security posture on all clients. ## Specification The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in [RFC 2119](https://www.rfc-editor.org/rfc/rfc2119) and [RFC 8174](https://www.rfc-editor.org/rfc/rfc8174). HTTP fields, derived components, and signature parameters are to be interpreted as defined in [RFC 9421](https://www.rfc-editor.org/rfc/rfc9421#name-http-message-components). Structured Fields are parsed as defined in [RFC 9651](https://www.rfc-editor.org/rfc/rfc9651). ### Overview This specification defines an Ethereum authentication scheme for HTTP requests using HTTP Message Signatures. Unless explicitly stated otherwise, implementations MUST reuse [RFC 9421](https://www.rfc-editor.org/rfc/rfc9421) for covered components, canonicalization, signature base construction, and the `Signature-Input` / `Signature` header syntax. The specification defines the Ethereum bindings: required signature parameters, the `keyid` format, and signing and verification semantics for Externally Owned Accounts (EOAs) and Smart Contract Accounts (SCAs). Security semantics are expressed directly through two orthogonal dimensions: - **request binding** (how tightly a signature is bound to a specific request) - **replay protection** (whether a signature can be reused). No out-of-band negotiation or capability discovery is required for verification. A signer selects which components and parameters to sign. A verifier evaluates whether the resulting signature satisfies the acceptance rules defined by the specification. Section 7 defines optional advisory discovery so a signer can select a compatible Account and security posture before its first request; the request and any runtime challenge remain authoritative. In this model, the signer explicitly chooses the security posture of each request by deciding what to cryptographically bind and whether to enable replay protection. The verifier does not issue credentials or negotiate risk levels, but simply evaluates the guarantees presented in the request. ### 1. Definitions - **Account**: any Ethereum account, either an Externally Owned Account (EOA) or a Smart Contract Account (SCA). - **EOA**: an Externally Owned Account controlled by a private key. - **SCA**: a Smart Contract Account that validates signatures via onchain logic (e.g. ERC-1271). - **Signer**: the Account that generates a signature for a request. - **Verifier**: the HTTP server (or gateway) verifying a signature on a received request. - **Request Signature**: an RFC 9421 signature under this profile whose `keyid` Account is both the Principal and Signer. - **Request-Bound**: a binding model in which a signature authorizes exactly one concrete HTTP request by covering the components specified in Section 3.1.1. - **Class-Bound**: a binding model with coverage below the Request-Bound baseline. Acceptance is a separate verifier policy. - **Non-Replayable**: a property of a signature that ensures it cannot be validly reused. - **Replayable**: a property of a signature that allows reuse within its validity window. - **Principal**: the Account against which application authorization is evaluated. ### 2. Headers Signers MUST attach signatures to HTTP requests using the [RFC 9421](https://www.rfc-editor.org/rfc/rfc9421#name-including-a-message-signatu) header fields: - `Signature-Input`: carries the list of covered components and signature parameters. - `Signature`: carries the signature bytes for the corresponding label. Labels are arbitrary transport keys and carry no security semantics. This example is illustrative; the [test vectors](../assets/eip-8128/test-vectors.md) contain verified values: ```text Signature-Input: request=("@scheme" "@authority" "@method" "@path" \ "@query");created=1700000000;expires=1700000060;\ nonce="b64url_r4Nd0mN0nCEK0YQY4d4r7A";\ keyid="eip155:1:0xd8da6bf26964af9d7eed9e03e53415d37aa96045";\ tag="erc8128" Signature: request=:dmSonRcA8ydqKFPQ+/f/dN2I0XviLbXIO4VPl9/41l5byGyBYO1SXY9eWixdKvB6cOaw96kUKFg50LZ60255jhs=: ``` The signed `tag` parameter identifies the signature class. A Request Signature has exactly the RFC 9421 String `tag="erc8128"`. An absent, non-String, or different last-wins `tag` does not identify a candidate of this profile. A verifier MUST NOT reinterpret a differently tagged signature as this profile's authentication after that other class fails. Other tags are not candidates of this profile. ### 3. Signature #### 3.1 Security Model The profile expresses all security semantics directly through two orthogonal dimensions: **request binding** and **replay protection**. ##### 3.1.1 Request Binding A signature is **Request-Bound** if it binds authorization to a specific received HTTP request. A Request-Bound signature MUST cover at minimum these exact, parameterless component identifiers: 1. `@scheme` 2. `@authority` 3. `@method` 4. `@path` 5. `@query` The order of these covered components is not significant to the Request-Bound classification. Their received order remains significant to the RFC 9421 signature base. `@query` MUST be covered even when its value is `?`. The verifier evaluates coverage against the request it received after reconstructing the effective target URI using trusted deployment configuration. It MUST NOT infer adequate binding from components the signer happened to cover. Whenever a `Content-Digest` field is received, the signature MUST also cover the exact parameterless `content-digest` field component. A signer sending non-empty content MUST send `Content-Digest`. Whenever `Content-Type` is received, including on a request with empty content, the signature MUST cover the exact parameterless `content-type` field component. Applications SHOULD additionally require coverage of components whose alteration can change authorization or interpretation of the authenticated operation, following [RFC 9421 Section 7.2.1](https://www.rfc-editor.org/rfc/rfc9421#section-7.2.1). Omitting any component required by this baseline yields `insufficient_coverage`. A signature that omits one or more components from the Request-Bound list is **Class-Bound**. A Class-Bound signature authorizes a class of requests defined by the covered components and any application-specific parameters. A verifier MAY accept it only under explicit route policy. Verifiers MUST be capable of accepting signatures that satisfy the Request-Bound requirements in this section, subject to application authorization policy. Verifiers MAY require additional application-specific components as a condition for acceptance. ##### 3.1.2 Replay Protection A signature is **Non-Replayable** if it cannot be validly reused. - Non-Replayable signatures MUST include an RFC 9421 String `nonce`. - Verifiers MUST enforce uniqueness of (`keyid`, `nonce`) within the accepted validity window, including allowed clock skew. - Verifiers MUST reject a Non-Replayable signature if its validity window exceeds the period for which replay state can be retained; this yields `request_validity_too_long`. - Once a nonce has been accepted, it MUST NOT be accepted again within that window. When a route requires Non-Replayable authentication, absence of `nonce` yields `nonce_required`. When a verifier supports Replayable signatures but the route or Principal policy rejects one, it yields `replayable_not_allowed`. The nonce MUST be ASCII and no more than 128 bytes. A present nonce of another Structured Field type, containing non-ASCII data, or exceeding 128 ASCII bytes yields `invalid_nonce`. Unless the verifier supplies the nonce, the signer MUST generate at least 128 bits of randomness for it. This entropy requirement is not enforceable by the verifier; inadequate entropy primarily causes signer self-denial through accidental `nonce_reused` collisions. The replay key is the collision-free tuple of the canonical CAIP-10 Signer ID and nonce. A verifier MUST atomically mark an unused replay key as used; finding it already used yields `nonce_reused`. It MUST retain the mark until the request can no longer be accepted, including allowed clock skew. A separate check followed by insertion is non-conforming. The verifier MUST consume the nonce only for a fully authenticated and policy-compatible winning candidate, after content and cryptographic verification. A failed candidate MUST NOT consume a nonce. A signature that omits `nonce` is **Replayable** and may be reused within its validity window, subject to verifier policy. A Replayable signature whose validity window is at most 60 seconds is invalidated by expiration alone, so a verifier accepts it without an early-invalidation check. A verifier accepting Replayable signatures with longer validity windows MUST implement a signer-triggerable early-invalidation mechanism, such as a per-Signer not-before time or per-signature denial entry, as defined in Section 5.2. A client request changing invalidation state MUST itself use a Request-Bound, Non-Replayable Request Signature. ##### 3.1.3 Content Integrity A signer sending non-empty content MUST generate `Content-Digest` over the exact content bytes according to [RFC 9530](https://www.rfc-editor.org/rfc/rfc9530). Missing that required field yields `content_digest_required`. A verifier has two digest-algorithm sets: - **supported**: `sha-256` MUST be supported and `sha-512` MAY be supported; - **unsupported**: every other algorithm, which is ignored. When `Content-Digest` is received, the verifier MUST parse the combined field value as an RFC 9530 and RFC 9651 Dictionary, recompute and match every supported member present, and require at least one supported member to be present and match. A syntax error, a supported member of the wrong type or length, a supported mismatch, or absence of a supported member yields `bad_content_digest`. Empty-content requests do not require the field, but a received field is verified by the same rules. #### 3.2 Conformance and Acceptance Rules ##### 3.2.1 Baseline Requirement To claim conformance with the proposal, implementations MUST be capable of accepting a Request Signature that is: - **Request-Bound**, and - **Non-Replayable**. This guarantees that a signer who chooses the strongest security posture — Request-Bound and Non-Replayable — can interoperate with any compliant verifier, subject to application authorization policy. Any implementation that is not capable of accepting signatures satisfying both properties is NOT compliant with the proposal. ##### 3.2.2 Optional Acceptance In addition to the baseline requirement, verifiers MAY accept signatures that relax one or both security dimensions: - **Replayable** signatures, - **Class-Bound** signatures, or - signatures that are both Replayable and Class-Bound. Verifiers that accept Replayable signatures whose validity window exceeds 60 seconds MUST implement the early invalidation mechanisms defined in Section 5.2. Except for signatures that satisfy the baseline requirement in Section 3.2.1, a verifier MAY reject any signature that does not satisfy its acceptance policy, even if the signature is otherwise valid under the specification. Principal policy is application-level authorization outside profile conformance; its rejection yields `principal_not_allowed`. #### 3.3 Signature Parameters ##### 3.3.1 `keyid` `keyid` MUST be an RFC 9421 String identifying an Account using canonical [CAIP-10](https://github.com/ChainAgnostic/CAIPs/blob/ad0cfebc45a4b8368628340bf22aefb2a5edcab7/CAIPs/caip-10.md) syntax: ```text eip155::
``` `` MUST be the unsigned base-10 chain ID from [EIP-155](./eip-155.md), with no leading zeroes. `
` MUST be `0x` followed by exactly 40 lowercase hexadecimal characters. Verifiers MUST use this canonical form for cache and replay keys. A missing, non-String, or syntactically invalid `keyid` on a candidate yields `invalid_keyid`. The chain ID selects the state used for [ERC-6492](./eip-6492.md) and [ERC-1271](./eip-1271.md) verification; a verifier MUST NOT query another chain. A syntactically valid `keyid` whose chain is not served by the verifier yields `unsupported_chain`. ##### 3.3.2 `created`, `expires` - `created` is an RFC 9421 Integer containing a Unix timestamp in seconds. - `expires` is an RFC 9421 Integer containing a Unix timestamp in seconds and MUST be greater than `created`. Verifiers MUST reject signatures whose `created` or `expires` parameter is missing or is not an Integer, or whose `expires` is not greater than `created`; these conditions yield `invalid_time`. The validity window `expires - created` bounds how long the signature can authenticate a request, how long the verifier retains replay state for a Non-Replayable signature, and whether early invalidation applies to a Replayable one (Section 5.2): a shorter window narrows replay exposure and verifier state, while a longer one tolerates more delivery latency and clock drift. Signers SHOULD choose the shortest window their delivery path and clock uncertainty allow, and MAY choose any length. Verifiers bound the window by route policy: a route MAY enforce any documented maximum suited to its architecture, and a window exceeding it yields `request_validity_too_long`. As the interoperability floor, a baseline route MUST accept validity windows up to 60 seconds, so a signer without knowledge of route policy can rely on any window of at most 60 seconds being accepted. Verifiers SHOULD allow 30 seconds of clock skew. With allowed skew `s`, the request is time-valid exactly when: ```text created - s <= now <= expires + s ``` `now < created - s` yields `request_not_yet_valid`; `now > expires + s` yields `request_expired`. ##### 3.3.3 `nonce` The `nonce` parameter is used to prevent replay. Its semantics are defined in Section 3.1.2. ##### 3.3.4 `tag`, `alg` `tag` is mandatory and identifies the class as specified in Section 2. Until an algorithm representing this scheme is registered in the IANA HTTP Signature Algorithms registry and this profile is revised to permit it, every Request Signature MUST omit RFC 9421's `alg`. A candidate containing `alg` yields `unsupported_algorithm`; a verifier MUST NOT use `alg` to select account behavior. ##### 3.3.5 `mode` `mode` is an OPTIONAL RFC 9421 String parameter whose only defined value is `"eoa"`. It lets the verifier skip the account-code lookup as specified in Section 4.1. A signer SHOULD include `mode="eoa"` only when the `keyid` Account has no code and the signature is a strict EOA signature under Section 3.4.3. Verifiers SHOULD honor it; a verifier that ignores it performs Universal Account verification unchanged. A `mode` parameter with any other value or type is ignored. The parameter is intended for registration in the HTTP Signature Metadata Parameters registry. #### 3.4 Signing ##### 3.4.1 Mandatory Parameters All Request Signatures MUST include the following parameters in `Signature-Input` and `@signature-params`: - `keyid` (Section 3.3.1) - `created` (Section 3.3.2) - `expires` (Section 3.3.2) - `tag` (Section 3.3.4) Signatures that are intended to be Non-Replayable MUST include the `nonce` parameter as defined in Section 3.1.2. Signers MAY include `mode` as defined in Section 3.3.5. ##### 3.4.2 Mandatory Components Signatures that are intended to be Request-Bound MUST satisfy the component requirements in Section 3.1.1. All Request Signatures MUST cover at least the `@authority` derived component. Verifiers MAY require additional covered components as a condition for accepting a signature. A signature that does not include the components required by the verifier's acceptance rules yields `insufficient_coverage`. ##### 3.4.3 Signature Construction The signature base `M` and component canonicalization MUST be constructed according to [RFC 9421](https://www.rfc-editor.org/rfc/rfc9421#name-creating-the-signature-base). Let `M` be the signature base for the selected label. Component and parameter order shown in examples is exemplary; the component and parameter order received in `Signature-Input` governs signature-base reconstruction and MUST remain unchanged for the life of the signature. ```text NOTE: `\` line wrapping per RFC 8792 (documentation only). ``` ```text "@scheme": https "@authority": api.example.com "@method": POST "@path": /foo "@query": ?a=1&b=two "content-digest": sha-256=:ungWv48Bz+pBQUDeXa4iI7ADYaOWF3qctBD/YfIAFa0=: "content-type": application/json "@signature-params": ("@scheme" "@authority" "@method" "@path" "@query" \ "content-digest" "content-type");created=1736940000;expires=1736940060;\ nonce="b64url_r4Nd0mN0nCEK0YQY4d4r7A";\ keyid="eip155:1:0xd8da6bf26964af9d7eed9e03e53415d37aa96045";tag="erc8128" ``` This profile applies the [ERC-191](./eip-191.md) `personal_sign` encoding directly to `M`: ```text H = keccak256("\x19Ethereum Signed Message:\n" || decimal(byteLength(M)) || M) ``` `byteLength(M)` is the length of the serialized signature base in bytes. The decimal length has no leading zeroes. [ERC-1271](./eip-1271.md) and [ERC-6492](./eip-6492.md) verification receive `H`, not a second hash and not the unhashed `M`. An EOA signature MUST be exactly 65 bytes `r || s || v`, with `1 <= r < secp256k1n`, `1 <= s <= secp256k1n / 2`, and `v` exactly 27 or 28. Compact, DER, high-`s`, EIP-155 transaction, and 0/1-`v` encodings are invalid. The recovered address MUST equal the normalized `keyid` address. SCA signatures are opaque byte strings and do not use this encoding rule. #### 3.5 Candidate Evaluation and Limits Before candidate evaluation, the verifier MUST combine and parse each `Signature-Input` and `Signature` field according to RFC 9421 and RFC 9651. A missing field yields `signature_missing`. A Structured Field syntax error in either field yields the whole-message failure `signature_input_invalid`; no candidate is evaluated. A well-formed tagged `Signature-Input` member without a correlated RFC 9421 Byte Sequence in `Signature` yields the candidate failure `signature_input_invalid`, and evaluation continues. Other well-formed candidates that fail profile validation are likewise skippable. Candidates are selected only by the exact last-wins String `tag="erc8128"` in `Signature-Input`. They MUST be evaluated in Dictionary wire order. A verifier MUST enforce limits before cryptography. Defaults are: | Input | Default limit | | --- | ---: | | Combined `Signature-Input` field | 16 KiB | | Combined `Signature` field | 16 KiB | | Decoded signature member | 8 KiB | | Recognized profile candidates per request | 8 | | Covered components per candidate | 32 | | Signature parameters per candidate | 16 | Exceeding either field/member size or the component/parameter count yields `signature_too_large`. Having more than the candidate budget also yields `signature_too_large`; this code therefore covers both byte-size and count limits. Deployments MAY use smaller documented limits. For each candidate, bounded parsing, time, coverage, digest, Principal-policy, and replay-posture checks precede cryptography. The first candidate passing all checks and atomically consuming its nonce, when present, wins. If no candidate wins and no more specific failure is available, evaluation yields `no_acceptable_signature`. Implementations MAY reorder checks when the externally observable result is identical, including HTTP status, reason code, nonce consumption, and RPC side effects. Limit checks MUST precede cryptography, failed candidates MUST NOT consume nonces, and the winning nonce MUST be consumed last. ### 4. Verification Given a request containing `Signature-Input` and `Signature`, the verifier evaluates each candidate as follows: 1. Parse the covered components, signature parameters, and signature bytes `S` per RFC 9421. 2. Parse `keyid`, extract the chain ID and address, and confirm that the verifier serves that chain. 3. Enforce the requirements in Sections 3 and 4, including route policy, time, content, and request coverage. 4. Reconstruct the signature base `M` per RFC 9421 using the received request and received `Signature-Input` order. 5. Compute `H` from `M` as defined in Section 3.4.3. 6. Perform Universal Account verification. An invalid cryptographic result yields `bad_signature`. A state-provider or RPC failure preventing classification or verification yields `signature_verification_unavailable`, not `bad_signature`. #### 4.1 Universal Account Verification Universal Account verification MUST proceed in this order: 1. If the signature is an [ERC-6492](./eip-6492.md) wrapper, verify the wrapper before inspecting account code. An invalid wrapper MUST NOT fall back. 2. Otherwise, if the candidate has `mode="eoa"` and the verifier honors it, apply strict local EOA recovery. If the recovered address equals the `keyid` address, the signature is valid without an account-code lookup. Otherwise, continue with step 3. 3. Obtain account code on the `keyid` chain. If code is present, including an [EIP-7702](./eip-7702.md) delegation indicator, call [ERC-1271](./eip-1271.md) with `H` and the opaque signature. An invalid call MUST NOT fall back to ECDSA. 4. Only for an unwrapped Account without code, apply strict local EOA recovery. With `mode="eoa"`, a signature that recovers locally requires no RPC. A signature that does not recover, including a contract-account signature sent with `mode="eoa"`, is verified as if `mode` were absent. #### 4.2 Failure Selection If no candidate wins and at least one otherwise policy-compatible candidate reaches an unavailable result, the verifier SHOULD return the first such result in wire order. Otherwise, it SHOULD return the failure for the first recognized candidate. This selection is implementation guidance for interoperability; implementations need not expose unobservable internal check ordering. A failing candidate never masks a later successful candidate. ### 5. Signature Invalidation #### 5.1 Non-Replayable Invalidation Non-Replayable signatures are invalidated by nonce consumption. - Nonces MUST be consumed atomically only after successful authentication. - Replay state MUST be shared across concurrent verifier instances. - Verifiers MUST retain replay state until `expires + allowed_skew` has passed. #### 5.2 Replayable Invalidation Replayable signatures are invalidated primarily by expiration. A Replayable signature whose validity window `expires - created` is at most 60 seconds is invalidated by expiration alone. Accepting it requires no early-invalidation mechanism, and a verifier does not consult early-invalidation state for it. Signers MUST NOT rely on early invalidation for such a signature. A Replayable signature with a longer validity window does not provide cryptographic replay protection for that longer period. Verifiers that accept such signatures MUST implement one or more early invalidation mechanisms that can be triggered by the signer. Such mechanisms MUST include at least one of the following: - per-`keyid` not-before timestamps - per-signature invalidation (e.g., fingerprinting of the signature or signature base) Any client-callable request that triggers early invalidation MUST be authenticated with a Request-Bound, Non-Replayable signature. Verifiers that do not implement early invalidation MUST NOT accept Replayable signatures whose validity window exceeds 60 seconds; such a signature yields `request_validity_too_long`. #### 5.3 Key Compromise and Rotation If an EOA is compromised, verifiers SHOULD rely on policy invalidation. For SCAs, changes in contract state MAY invalidate previously issued signatures, depending on the ERC-1271 implementation. ### 6. Failure Responses `signature_input_invalid` and `signature_too_large` use HTTP 400. `signature_verification_unavailable` uses HTTP 503 and MAY include `Retry-After`. Every other failure below, including `unsupported_chain`, is an authentication rejection and uses HTTP 401. HTTP 403 is reserved for application authorization denied after a Request Signature has verified. A verifier MUST NOT return 403 for a signature-layer failure or consume a nonce for a request it denies. Every 401 response MUST include a challenge applicable to the target resource: ```http WWW-Authenticate: ERC8128 error="bad_signature" ``` The case-insensitive provisional authentication scheme token is `ERC8128`. Its optional `error` auth-param carries one reason code from this section, using quoted-string syntax. The scheme is intended for provisional IANA registration, and senders SHOULD use `ERC8128` as the preferred capitalization. A challenge MAY include `chains`, an ASCII-space-separated list of canonical CAIP-2 `eip155` chain IDs served by the verifier. A verifier returning `unsupported_chain` SHOULD include `chains` unless exposing that policy to an unauthenticated caller is a disclosure risk. The parameter describes what would satisfy the challenged route: ```http WWW-Authenticate: ERC8128 error="unsupported_chain", chains="eip155:1 eip155:8453" ``` When a response body is sent, it SHOULD use [RFC 9457](https://www.rfc-editor.org/rfc/rfc9457) `application/problem+json` and MUST include the same stable code in a `reason` extension. Failure details MUST NOT expose contract revert data, private policy, or sensitive content. Whenever a route requires covered components beyond the Request-Bound baseline, its challenge SHOULD return [RFC 9421](https://www.rfc-editor.org/rfc/rfc9421#section-5) `Accept-Signature`. Each advertised member MUST enumerate, in the required order, the complete and exact component set for that label: the Request-Bound baseline, every route-required component, `content-digest` for a non-empty request body, and `content-type` when that field will be present. A verifier returning `insufficient_coverage` SHOULD include the same field unless exposing route requirements to an unauthenticated caller is a disclosure risk. For example, a repair response to a body-bearing request can advertise: ```http WWW-Authenticate: ERC8128 error="insufficient_coverage" Accept-Signature: request=("@scheme" "@authority" "@method" "@path" "@query" "content-digest" "content-type");created;expires;tag="erc8128" ``` The bare `created` and `expires` parameters request the RFC 9421 creation and expiration values, while `tag` carries this profile's explicit String value. The signer adds its selected canonical String `keyid` and, when non-replayability is required, generates a fresh `nonce` satisfying Section 3.1.2. A verifier MAY issue the nonce by advertising its actual value in `Accept-Signature`, for example `;nonce="b64url_r4Nd0mN0nCEK0YQY4d4r7A"`. `Accept-Signature` is a repair hint and does not weaken verifier policy. The runtime challenge is authoritative over discovery metadata. A retry MUST use the advertised label and cover exactly the listed component identifiers in the listed order; it MUST NOT append other covered components to that signature. The signer MAY add signature parameters permitted by RFC 9421 and this profile. If it needs to cover a different component set, it does so with a separate signature under another label. The stable codes are: ```text signature_missing signature_input_invalid signature_too_large no_acceptable_signature invalid_keyid unsupported_chain invalid_time request_not_yet_valid request_expired request_validity_too_long invalid_nonce insufficient_coverage content_digest_required bad_content_digest nonce_required nonce_reused replayable_not_allowed unsupported_algorithm bad_signature signature_verification_unavailable principal_not_allowed ``` This non-normative index maps each code to its principal condition: | Code | Condition | | --- | --- | | `signature_missing` | A signature field is absent | | `signature_input_invalid` | A signature field is SF-malformed or members cannot correlate | | `signature_too_large` | A byte or count limit is exceeded | | `no_acceptable_signature` | No candidate wins and no specific candidate failure applies | | `invalid_keyid` | Candidate `keyid` is invalid | | `unsupported_chain` | The verifier does not serve the syntactically valid `keyid` chain | | `invalid_time` | Required time metadata is structurally invalid | | `request_not_yet_valid` | Current time precedes the skew-adjusted window | | `request_expired` | Current time follows the skew-adjusted window | | `request_validity_too_long` | The route maximum is exceeded, or a verifier without early invalidation receives a Replayable signature valid for more than 60 seconds | | `invalid_nonce` | A present nonce has an invalid type or size | | `insufficient_coverage` | Request-Bound or route-required coverage is missing | | `content_digest_required` | Non-empty content lacks `Content-Digest` | | `bad_content_digest` | A received digest is invalid or does not verify | | `nonce_required` | Non-Replayable policy requires a nonce | | `nonce_reused` | Atomic replay-key insertion fails | | `replayable_not_allowed` | Replayable posture is rejected | | `unsupported_algorithm` | A candidate contains `alg` | | `bad_signature` | Cryptographic verification is definitive and invalid | | `signature_verification_unavailable` | Account classification or verification is unavailable | | `principal_not_allowed` | Application Principal policy rejects the Account | ### 7. Advisory Discovery Document An HTTPS origin MAY publish a discovery document for this profile at `/.well-known/erc8128`, following the well-known URI rules in [RFC 8615](https://www.rfc-editor.org/rfc/rfc8615). The document is a UTF-8 JSON object served with `Content-Type: application/json`. Fetching it is OPTIONAL: a verifier MUST be able to verify a request without the document, and a signer MUST be able to use the baseline profile without fetching it. The document advertises policy; it does not grant authority and is never an input to signature verification. A runtime `WWW-Authenticate` or `Accept-Signature` challenge is authoritative for the next request when it differs from a cached document. A client MUST NOT interpret an omitted member as support for every value in that category. Clients MUST ignore unrecognized members so that the document can be extended. This example shows all defined members: ```json { "max_validity_sec": 300, "chains": ["eip155:1", "eip155:8453"], "invalidation_endpoint": "https://api.example/signatures/invalidate", "name": "Example Merchant API", "logo_uri": "https://api.example/logo.svg", "terms_uri": "https://api.example/terms", "privacy_uri": "https://api.example/privacy", "payment_challenges": true, "scopes": { "orders:create": "Create an order" }, "delegation": { "max_depth": 2, "registry_chains": ["eip155:1"] }, "route_policies": { "/orders": { "methods": ["POST"], "max_validity_sec": 60, "required_components": ["content-digest", "content-type"], "content_digest": "required", "scopes": ["orders:create"], "audience": "https://api.example", "max_depth": 2 }, "/catalog/*": { "methods": ["GET"], "max_validity_sec": 60, "replayable": "allowed" } } } ``` The top-level members are: | Member | Type and meaning | | --- | --- | | `max_validity_sec` | Positive integer maximum for `expires - created` when a route does not override it | | `chains` | Non-empty array of canonical CAIP-2 `eip155` chain IDs the verifier serves | | `invalidation_endpoint` | Absolute same-origin HTTPS URL implementing Section 5.2 early invalidation | | `name` | Human-readable resource name | | `logo_uri` | Absolute HTTPS URL for a resource logo | | `terms_uri` | Absolute HTTPS URL for the resource's terms | | `privacy_uri` | Absolute HTTPS URL for the resource's privacy policy | | `payment_challenges` | Boolean indicating that routes may issue complementary payment challenges | | `scopes` | Object mapping case-sensitive scope strings to human-readable descriptions | | `delegation` | Delegated-authentication support metadata containing positive integer `max_depth` and non-empty `registry_chains` | | `route_policies` | Object mapping route patterns to one policy object or a non-empty array of policy objects | All members are OPTIONAL. Numeric values MUST be JSON integers in the interoperable range `1` through `9007199254740991`. Account and chain identifiers, origins, component identifiers, and URLs MUST be canonical under the specifications that define them. Human-readable strings and fetched images are untrusted presentation input; a client MUST sanitize them and MUST display the resource origin with them. A route policy has these members: | Member | Type and meaning | | --- | --- | | `methods` | Non-empty array of case-sensitive HTTP method tokens as defined by [RFC 9110](https://www.rfc-editor.org/rfc/rfc9110#section-9.1); omission applies the policy to every method | | `max_validity_sec` | Positive integer route override for the validity maximum | | `required_components` | Array of RFC 9421 component identifiers, serialized without signature-base outer quotes, required in addition to the applicable Section 3.1.1 requirements | | `replayable` | `allowed` when the route also accepts Replayable signatures; absent, the route requires a nonce. Without an `invalidation_endpoint`, a client SHOULD keep Replayable validity windows to at most 60 seconds (Section 5.2) | | `content_digest` | `request-body` for the Section 3.1.3 baseline, or `required` to require `Content-Digest` even with empty content | | `scopes` | Non-empty array of case-sensitive scopes required by the route under AND semantics | | `audience` | Canonical HTTPS origin a delegation grant must name | | `max_depth` | Positive integer delegation-chain depth maximum; its presence indicates delegated-signature support | Route keys are either an absolute path, an absolute path ending in `/*`, or `default`. An exact path wins over a wildcard; among matching wildcards, the longest prefix wins; `default` applies only when no path key matches. When a selected key contains an array, the first policy whose `methods` contains an exact, octet-for-octet match for the case-sensitive request method wins; implementations MUST NOT case-fold either value. Otherwise, the first policy without `methods` applies. Thus `POST` and `post` select different policies. If a path key matches but has no policy for the method, no lower-precedence route policy applies. Object member order otherwise carries no preference. The decoded document SHOULD be no larger than 64 KiB and SHOULD use normal HTTP cache controls. A client MUST enforce a response limit no greater than 65,536 decoded octets, stop reading when the limit is crossed, and reject the document before parsing it. It MUST use a JSON parser with bounded nesting depth, member count, aggregate string length, and allocation, and MUST apply finite connection, read, and overall retrieval timeouts. Discovery metadata MUST NOT be required to be fresh for request verification. Endpoints and presentation URLs in the document MUST NOT be treated as trusted merely because the discovery document was retrieved over HTTPS. Such URLs SHOULD be same-origin. An automated client fetching `logo_uri`, `terms_uri`, `privacy_uri`, `invalidation_endpoint`, or any future URL MUST omit cookies, HTTP authentication, client credentials, and other ambient authority. It MUST either require the target and every redirect hop to remain same-origin or apply redirect-aware egress controls that reject loopback, link-local, private-network, and other non-public destinations after every DNS resolution and protect against DNS rebinding. Logo fetches MUST additionally enforce independent byte, media-type, image-dimension, and decoding limits and MUST NOT execute active image content. Human-readable strings remain untrusted presentation input and MUST be sanitized while displaying the resource origin. The `erc8128` suffix is intended for provisional registration in the Well-Known URIs registry. ## Rationale ### Design Goals The proposal is designed with two primary goals: 1. **Zero-handshake interoperability** Enable a signer to interact securely with any verifier compliant with the proposal without requiring a prior handshake or "login" / session-establishment step. Whether a request is accepted is determined solely by signature verification and the acceptance rules defined in this document (i.e., no server-issued bearer token is required as a prerequisite for authenticated requests). 2. **Security-first by default** Ensure that the strongest security posture — **Request-Bound and Non-Replayable** — is always supported by any compliant verifier. At the same time, allow applications to opt into mechanisms with explicit security/performance tradeoffs (e.g., replayable or class-bound authorization) without fragmenting the standard. This guarantees that: - a signer that requires a low-risk posture (Request-Bound + Non-Replayable) can interact with any compliant verifier, and - no verifier can claim conformance while only supporting weaker or application-specific security models. ### Why the Baseline Requires Request-Bound and Non-Replayable The baseline requirement enforces both properties because together they provide: - **Request Integrity:** Request-Bound signatures prevent retargeting and confused-deputy attacks by cryptographically binding authorization to a specific HTTP request. - **Freshness and Single-Use Authorization:** Non-Replayable signatures prevent reuse of captured requests across networks, proxies, or logs. These properties are essential for APIs that authorize state changes, payments, or other sensitive operations. Optional acceptance of weaker properties exists solely for explicitly performance-driven or idempotent use cases. The mandatory replay state is bounded: a verifier needs to keep each consumed nonce only until the signature's skew-adjusted expiry. Routes for which even that per-request state is disproportionate can additionally accept the Replayable posture under Section 5.2, which needs no shared replay or invalidation state for a validity window of at most 60 seconds; the baseline itself is never weakened. A verifier never treats a nonce-bearing signature as Replayable, because the signed nonce records the signer's choice of single use: the verifier either consumes it atomically or rejects the request. ### Signer-Defined Security Posture The proposal is built on the principle that the entity authorizing an action should be able to choose the exact security guarantees attached to that action. Rather than embedding risk levels in server-issued tokens, session state, or out-of-band policy, security is expressed directly in the cryptographic material of each request: which components are bound, whether the request is replayable, and how long it remains valid. This enables: - fine-grained, per-request control over authorization strength, - verifiers that do not need to issue or store bearer session credentials, - composable authorization for agents, services, and onchain identities that operate without prior trust relationships. ### Authentication of Replayable Invalidation Early invalidation changes authorization state. Request binding identifies the exact invalidation operation, and nonce consumption prevents the control request from being reused. ### Why short Replayable signatures need no early invalidation The short-window exemption makes an explicit tradeoff: the signer accepts repeated use until the signature's skew-adjusted expiry in exchange for avoiding shared replay and invalidation state. Even when a verifier implements early invalidation for longer-lived signatures, it does not consult that state for an exempt signature. Replayable signatures with longer validity windows require early invalidation under Section 5.2. The 60-second cutoff is a policy choice aligned with the interoperability floor of Section 3.3.2. It applies to the signed validity window `expires - created`; allowed clock skew extends the actual acceptance interval. The exemption removes shared replay and invalidation state, but Account verification and application authorization may still require state. Routes that cannot tolerate repeated delivery within the acceptance interval, such as non-idempotent operations, require Non-Replayable signatures instead. ### Why [ERC-191](./eip-191.md) over [EIP-712](./eip-712.md) The specification signs the RFC 9421 signature base `M`, which is a canonicalized byte sequence derived from HTTP message components. The primary requirement is that the signature binds to `M` in a deterministic, widely implementable way across wallets, agents, and server-side signers. ERC-191 (`personal_sign`) is chosen because it: - is broadly supported across Ethereum signing stacks (including non-interactive and machine-to-machine signers), - signs an arbitrary byte string without requiring a typed schema, domain separator, or UI-oriented metadata, - maps naturally to "sign exactly this canonical signature base `M`" as required by RFC 9421's model. EIP-712 is primarily designed for *structured* (typed) data and is often used to improve human inspectability and reduce phishing risk in interactive wallet flows. That advantage is less relevant here because HTTP message signatures are typically enforced programmatically by applications and agents, and many requests include non-human-friendly material (hashes, digests, nonces, etc.). On RFC 9421 compliance: using EIP-712 would not be "impossible", but it would not be a request signature over the RFC 9421 signature base `M` unless the EIP-712 typed data is defined to represent `M` exactly and canonically. That introduces an additional serialization layer (typed-data encoding + domain separation) and weakens interoperability with generic RFC 9421 tooling, which expects "signature = Sign(M)". For the proposal's goal — standardizing Ethereum bindings for RFC 9421 — ERC-191 is the simplest and most compatible choice. ### Why this is needed in addition to SIWE and other existing mechanisms SIWE (ERC-4361) is designed for interactive user authentication, where a user signs a statement to establish identity and a relying party typically issues a session (cookie/JWT) for subsequent requests. It does not standardize how to authenticate and provide integrity for arbitrary HTTP traffic (API clients, servers, agents) on a per-request basis without bearer credentials. The proposal targets the missing piece: authenticating *each HTTP request itself* using Ethereum accounts, with request integrity and replay protection, without relying on server-issued bearer credentials or long-lived sessions. It is intended for machine-to-machine communication, gateways, agents, and any environment where issuing, storing, and protecting shared secrets or sessions is undesirable. Existing payment or application-specific conventions may define how to express certain semantics (e.g., errors, payment requirements, or application-level metadata), but they do not standardize cryptographic request authentication, canonicalization, or replay protection in a way that is interoperable with RFC 9421. The proposal fills that gap. ### Signature replayability inference from `nonce` Earlier designs included an additional parameter to make the signer's intent unambiguous (i.e. `request-type="non-replayable"`) but it was ultimately removed as the presence of `nonce` directly and uniquely signals non-replayability, making the additional parameter redundant. ### Algorithm and profile signaling (`alg`, label, params) RFC 9421 defines an `alg` signature parameter whose values come from the IANA "HTTP Signature Algorithms" registry. Using `alg` could improve interoperability with generic RFC 9421 tooling by making the algorithm explicit and machine-discoverable. However, Ethereum signing as specified by the proposal (ERC-191 over the RFC 9421 signature base, signed with ECDSA over secp256k1, and verified via address recovery for EOAs or Universal Account verification) is not currently represented in that registry, and defining an unregistered `alg` value would reduce interoperability and create ambiguous behavior across implementations. For these reasons, the signed `tag` and `keyid` identify the profile and Request Signatures MUST omit `alg`. A future iteration could register an IANA `alg` identifier and update the profile to recognize it. Labels remain arbitrary transport keys. ### Algorithm agility Signature algorithms other than secp256k1 ECDSA are supported through account logic rather than HTTP signature metadata. An Account whose signers use another scheme, such as P-256 passkeys, authenticates through ERC-1271, including before deployment through ERC-6492, so verifiers need no algorithm signal from the request. `alg` never selects verification, and `mode` only enables a local check that falls back to Account state, which rules out algorithm confusion. An Account whose authorization follows from neither secp256k1 recovery nor ERC-1271 cannot authenticate under this profile and fails closed; supporting it requires a revision of this profile that selects verification from protocol-defined account state. ### Signer-declared EOA verification For a code-free EOA, the account-code lookup is the only RPC call verification needs. The signer knows whether its Account has code, so `mode="eoa"` lets it remove that call. The hint cannot authenticate anyone who could not already authenticate: no private key's signature recovers a contract account's address, and the key of an EIP-7702-delegated Account can change or clear its delegation onchain at any time. A signature that does not recover falls back to Universal Account verification, so an incorrect hint costs an RPC call but never rejects a valid signature. ### Single authoritative encoding Each proof has exactly one encoding: the RFC 9421 `Signature-Input` and `Signature` fields. This profile defines no fallback or alternative fields, because a second encoding of the same proof would need its own normalization rules and could be interpreted differently from the first. Where intermediaries cannot preserve these fields, deployments should verify at a trusted boundary before the fields are altered, or configure the intermediaries to forward them unchanged. ## Backwards Compatibility The proposal specifies an application-layer profile for RFC 9421 using the `Signature-Input` and `Signature` HTTP fields; non-supporting clients, servers, and intermediaries will ignore these as ordinary fields, allowing for incremental rollout. The profile can coexist with existing authentication (e.g., cookies, API keys, OAuth, SIWE); applications must define precedence if multiple mechanisms are accepted. The standard does not register a new RFC 9421 algorithm; implementations recognize the profile by its signed `tag` and `keyid` and apply Universal Account verification. ## Test Cases [Test vectors and expected results](../assets/eip-8128/test-vectors.md) cover request signatures, content integrity, replay protection, and failure cases. Implementations MUST test a replay race by submitting the positive request concurrently: exactly one request may authenticate. They MUST also test [ERC-6492](./eip-6492.md) before code lookup, [ERC-1271](./eip-1271.md) without ECDSA fallback for deployed and [EIP-7702](./eip-7702.md)-delegated Accounts, strict EOA recovery for a code-free Account, that `mode="eoa"` verifies a recovering signature without an account-code lookup and otherwise falls back to Universal Account verification, and that received legal parameter order is preserved. ## Reference Implementation [Signer and verifier pseudocode](../assets/eip-8128/reference-pseudocode.md) illustrates request signing and verification. ## Security Considerations ### Nonce handling models Replay protection requires state: verifiers must prevent reuse of the same authorization proof. The specification uses a `nonce` parameter for Non-Replayable signatures and defines replay prevention in terms of uniqueness of (`keyid`, `nonce`) within a retention window. The specification intentionally does not standardize *how* nonces are obtained (e.g., server-issued vs client-generated) because different deployment models have different constraints: - **Client-generated nonces** (e.g., random 128-bit) avoid an extra round-trip and work well for agents and offline signing, but require verifiers to store seen nonces. - **Server-issued nonces** (e.g., via an application endpoint) can enforce sequencing or tighter control, but introduce a handshake-like dependency and additional latency. To preserve zero-handshake interoperability, the specification standardizes the semantics: if `nonce` is present, the signature is Non-Replayable and verifiers must enforce uniqueness for the validity window they accept. Implementations are free to choose storage backends (in-memory, shared cache, database) and concurrency strategies appropriate for their scale and topology. Additionally, because nonce retention is stateful, verifiers must reject Non-Replayable signatures whose validity window exceeds what the verifier can safely retain nonce state for; otherwise "Non-Replayable" would not be a reliable property. ### Nonce enforcement and concurrency Verifiers must ensure that checking and consuming (`keyid`, `nonce`) is an atomic operation. In concurrent or distributed deployments, a non-atomic "check then insert" can allow two parallel verifications of the same nonce to both succeed due to a race condition. Implementations should use a shared store that supports atomic writes (e.g., transactional database writes or atomic operations in a shared cache) and must retain nonce state through the accepted signature's skew-adjusted expiry. A retry that needs a new authentication attempt uses a fresh nonce. Nonce consumption prevents proof reuse; it does not guarantee exactly-once application execution. Applications needing operation deduplication should bind their idempotency identifier into the signature and enforce it independently. ### Verification state Non-Replayable requests require shared atomic nonce state. Replayable requests valid for more than 60 seconds require the early-invalidation state in Section 5.2; those valid for at most 60 seconds require no shared replay or invalidation state. Both require Account verification under Section 4.1, including code classification unless a `mode="eoa"` signature recovers locally. This profile does not require an additional Principal-signature denylist or server-side session record. Application authorization remains independent. ### Why include Replayable and Class-Bound signatures The specification defines a security-first baseline (Request-Bound + Non-Replayable) that every compliant verifier must accept. However, real-world systems at scale sometimes need controlled tradeoffs for latency and cost. Replayable signatures can reduce repeated verification overhead when the same authorization proof is used multiple times within a short validity window. While each request still requires evaluation, verifiers can implement caching strategies (e.g., caching successful verification results keyed by signature bytes or by an application-defined authorization handle) to avoid repeating expensive cryptographic checks for identical proofs. This is most relevant for high-frequency clients and large-scale gateways, where repeated signature verification can become a material CPU cost. Replayable acceptance remains optional. A verifier accepting Replayable signatures valid for at most 60 seconds needs no shared replay or invalidation state, and acceptance of longer validity windows MUST be paired with robust early invalidation mechanisms. Class-Bound signatures allow a single authorization proof to apply to a *class of requests* (e.g., omitting `@query`), which can further reduce signer and verifier overhead in narrowly defined, low-risk use cases (e.g., idempotent reads, pre-authorized request classes). This flexibility is explicitly optional because it weakens request integrity guarantees compared to Request-Bound signatures. Implementations that support Replayable and/or Class-Bound modes should scope their use to low-risk operations and short validity windows, as these modes weaken integrity and/or replay guarantees by design. Finally, replayability and binding strength are decoupled to avoid forcing implementations into a small number of rigid modes. Different applications may want: - replayable but class-bound in constrained patterns (Replayable + Class-Bound), - strong binding but replayable within a short window (Replayable + Request-Bound), - non-replayable but class-bound in constrained patterns (Non-Replayable + Class-Bound), - or the baseline strongest posture (Non-Replayable + Request-Bound). The profile standardizes the baseline and defines the weaker modes as optional so implementations can adopt performance-driven tradeoffs without fragmenting interoperability. ### Account classification Without `mode="eoa"`, an EIP-7702-delegated EOA is verified through ERC-1271, and one whose implementation lacks `isValidSignature` cannot authenticate while it has code. That path permits no ECDSA fallback, so verification follows the Account's current implementation. This does not protect against compromise of the EOA key, which can change or clear the delegation onchain at any time. With `mode="eoa"`, a raw-key signature from an EIP-7702-delegated Account authenticates without consulting its implementation. This grants nothing the key cannot already obtain onchain, but such a bypass leaves no onchain trace. If a protocol mechanism for deactivating a delegated EOA's key is adopted, verifiers honoring `mode="eoa"` would accept a deactivated key until this profile is revised. ### Proxies and transformations Effective-target reconstruction is only as trustworthy as the proxy boundary. Verifiers must trust forwarding metadata only from configured proxies and document reconstruction. Intermediaries are not required to preserve signatures: path normalization, query rewriting, decompression, or any other transformation of a covered component will break a covering signature. ### HTTP caching The shared-cache restrictions for requests containing `Authorization` in [RFC 9111 Section 3.5](https://www.rfc-editor.org/rfc/rfc9111#section-3.5) do not automatically apply to `Signature` and `Signature-Input`. Applications are responsible for preventing unauthorized reuse of authenticated responses by caches. ### Interactive signing When available, wallets SHOULD obtain the requesting origin from trusted interaction context and display it distinctly from the signed target authority. A target chosen by the requesting application does not establish that application's trustworthiness. Clients MUST apply their own authorization policy before signing. ### Downgrade resistance Applications supporting multiple authentication systems must define precedence. A failed extension class must not fall back to this profile's authentication or a broader bearer credential. Principal policy remains application authorization and does not alter profile conformance. ### Duplicate Structured Field keys Structured Fields parsing resolves a duplicated Dictionary member or parameter key by keeping the last occurrence; this profile adds no duplicate-rejection layer, so an unmodified RFC 9651 parser is sufficient. Duplicates do not create an authentication gap: a discarded earlier occurrence is semantically inert, and the surviving last value is either covered by signature-base reconstruction or checked by a bound validation rule, so any effective change yields `bad_signature` or the corresponding failure. Repeated field lines of a covered ordinary field are likewise harmless, because they change the combined field value and therefore the reconstructed signature base. Verifiers must parse each field exactly once and evaluate every rule against the values that parse produced; validating one parse result while authenticating another reintroduces smuggling risk. ### Denial of service and state trust Limits and local policy checks precede cryptography and RPC. Deployments should rate-limit using network and application signals without treating unverified `keyid` values as authenticated. Universal Account verification inherits the freshness, finality, and availability of the selected chain-state provider. ### Discovery metadata Discovery is an integration hint, not an authorization source. A malicious or compromised origin can publish misleading names, images, scope descriptions, endpoints, and policies. Clients must render its strings as untrusted text, constrain image retrieval and decoding, keep credentials off metadata fetches, reject unsafe redirects, and show the origin independently of publisher-controlled branding. A stale document can cause a failed first request but cannot make a verifier accept a request outside its runtime policy. ### Privacy and confidentiality Stable Account IDs correlate requests. HTTP Message Signatures provide authenticity and integrity, not confidentiality; TLS remains required for non-public data. ## Copyright Copyright and related rights waived via [CC0](../LICENSE.md).