Are you an LLM? Read llms.txt for a summary of the docs, or llms-full.txt for the full context.
Specification – ERC-8128
Skip to content

Specification

ERC-8128 defines how Ethereum accounts sign HTTP requests using RFC 9421 (HTTP Message Signatures).

Full Specification: ERC-8128 on GitHub

Overview

ERC-8128 is a profile of RFC 9421 that specifies:

  1. Signature algorithm: Ethereum message signing (EIP-191)
  2. Key identification: erc8128:<chainId>:<address> format
  3. Default components: Request-bound signing
  4. Replay protection: Nonce-based with time bounds

Headers

Signature-Input

Structured Dictionary (RFC 8941) listing signed components and parameters:

Signature-Input: eth=("@authority" "@method" "@path" "@query" "content-digest");created=1618884473;expires=1618884533;nonce="abc123";keyid="erc8128:1:0xd8da6bf26964af9d7eed9e03e53415d37aa96045"
Required parameters:
  • created — Unix timestamp when signature was created
  • expires — Unix timestamp when signature expires
  • keyid — Signer identifier in erc8128:<chainId>:<address> format
Optional parameters:
  • nonce — Unique value for replay protection
  • tag — Application-specific tag

Signature

Structured Dictionary with base64-encoded signature:

Signature: eth=:MEUCIQDXtPCJ5f7oKr...base64...:

Content-Digest

SHA-256 hash of the request body (RFC 9530):

Content-Digest: sha-256=:X48E9qOokqqrvdts8nOJRJN3OWDUoyWxBf7kbu9DBPE=:

Keyid Format

The keyid parameter identifies the signer using an ERC-8128-specific URI format:

erc8128:<chainId>:<address>
  • chainId: Decimal integer (e.g., 1 for Ethereum mainnet)
  • address: Checksummed or lowercase Ethereum address with 0x prefix
Examples:
erc8128:1:0xd8da6bf26964af9d7eed9e03e53415d37aa96045
erc8128:8453:0x1234567890abcdef1234567890abcdef12345678
erc8128:42161:0xABCDEF1234567890ABCDEF1234567890ABCDEF12

Signature Base

The message signed is an RFC 9421 signature base — a canonical representation of the HTTP request:

"@authority": api.example.com
"@method": POST
"@path": /orders
"@query": ?market=ETH-USD
"content-digest": sha-256=:X48E9qOokqqrvdts8nOJRJN3OWDUoyWxBf7kbu9DBPE=:
"@signature-params": ("@authority" "@method" "@path" "@query" "content-digest");created=1618884473;expires=1618884533;nonce="abc123";keyid="erc8128:1:0xd8da6bf26964af9d7eed9e03e53415d37aa96045"

This is then signed as an Ethereum message:

keccak256("\x19Ethereum Signed Message:\n" + len(signatureBase) + signatureBase)

Binding Modes

Request-Bound

The signature MUST cover at minimum:

  • @authority
  • @method
  • @path
  • @query (if query string present)
  • content-digest (if body present)

Class-Bound

The signer explicitly specifies which components to sign. The verifier MUST enforce its own required components.

Replay Protection

Non-Replayable

  • nonce parameter MUST be present
  • Verifier MUST track consumed nonces
  • Verifier SHOULD reject if expires - created exceeds policy limit

Replayable

  • nonce parameter MAY be absent
  • Verifier MAY accept based on time bounds alone
  • SHOULD only be used for safe, idempotent operations

Signature Verification

EOA (Externally Owned Account)

  1. Reconstruct the signature base from the request
  2. Apply EIP-191 prefix: "\x19Ethereum Signed Message:\n" + length + message
  3. Recover the public key using ecrecover
  4. Derive address and compare to keyid address

SCA (Smart Contract Account)

  1. Reconstruct the signature base from the request
  2. Apply EIP-191 prefix
  3. Call isValidSignature(hash, signature) on the contract at keyid address
  4. Verify return value is 0x1626ba7e (ERC-1271 magic value)

Time Constraints

  • created MUST be a positive integer (Unix timestamp)
  • expires MUST be greater than created
  • Verifier SHOULD reject if now < created - clockSkew
  • Verifier MUST reject if now > expires + clockSkew
  • Verifier SHOULD enforce expires - created <= maxValiditySec

Error Codes

CodeMeaning
missing_headersNo Signature-Input or Signature header
label_not_foundRequested label not in Signature-Input
bad_signature_inputMalformed Signature-Input header
bad_signatureSignature verification failed
bad_keyidInvalid keyid format
bad_timeInvalid time parameters
not_yet_validSignature not yet valid
expiredSignature expired
validity_too_longValidity window exceeds policy
nonce_requiredNonce required but missing
replayable_not_allowedReplayable signature not accepted by policy
class_bound_not_allowedClass-bound signature not accepted by policy
nonce_window_too_longNonce validity window exceeds policy limit
replayNonce already consumed
not_request_boundRequired components not signed
digest_requiredContent-Digest header missing
digest_mismatchContent-Digest doesn't match body
alg_not_allowedSignature algorithm not permitted
bad_signature_bytesInvalid signature byte encoding
bad_signature_checkSignature verification function failed

References

  • RFC 9421 — HTTP Message Signatures
  • RFC 9530 — Digest Fields
  • RFC 8941 — Structured Field Values
  • EIP-191 — Signed Data Standard
  • ERC-1271 — Standard Signature Validation
  • ERC-6492 — Signature Validation for Pre-deploy Contracts