Concepts Overview
ERC-8128 combines three technologies to create a secure HTTP authentication system:
- RFC 9421 — HTTP Message Signatures standard
- EIP-191 — Ethereum Signed Message format
- ERC-1271 — Smart contract signature verification
The Problem
Traditional HTTP authentication has limitations:
- Bearer tokens (JWTs, API keys) can be stolen and reused
- Session cookies require server-side state
- OAuth requires a handshake and centralized identity providers
What if the client could prove their identity on every request using their existing Ethereum keys?
The Solution
ERC-8128 lets Ethereum accounts sign HTTP requests directly:
┌─────────────┐ Signed Request ┌─────────────┐
│ │ ───────────────────▶ │ │
│ Client │ Signature-Input │ Server │
│ (signer) │ Signature │ (verifier) │
│ │ Content-Digest │ │
└─────────────┘ └─────────────┘
│ │
│ Signs with ETH key │ Verifies signature
▼ ▼
┌─────────────┐ ┌─────────────┐
│ EOA │ │ ecrecover │
│ or │ │ or │
│ SCA │ │ ERC-1271 │
└─────────────┘ └─────────────┘Core Components
Signature Base
The "message" being 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:0x1234...abcd"This is signed as an Ethereum message (EIP-191).
Headers
Three headers carry the signature:
| Header | Purpose |
|---|---|
Signature-Input | Lists what was signed and parameters |
Signature | The cryptographic signature |
Content-Digest | SHA-256 hash of the body |
Example:
POST /orders HTTP/1.1
Host: api.example.com
Content-Type: application/json
Signature-Input: eth=("@authority" "@method" "@path" "content-digest");created=1618884473;expires=1618884533;nonce="abc123";keyid="erc8128:1:0x1234...abcd"
Signature: eth=:MEUCIQDXtPCJ5...base64...:
Content-Digest: sha-256=:X48E9qOokqqrvdts8nOJRJN3OWDUoyWxBf7kbu9DBPE=:
{"amount": "100"}Keyid Format
The keyid identifies the signer:
erc8128:<chainId>:<address>Examples:
erc8128:1:0xd8da6bf26964af9d7eed9e03e53415d37aa96045— Ethereum mainneterc8128:8453:0x1234...abcd— Baseerc8128:42161:0x1234...abcd— Arbitrum
Security Properties
| Property | How It's Achieved |
|---|---|
| Authentication | Signature proves knowledge of private key |
| Integrity | Tampering with signed components fails verification |
| Replay Protection | Nonce prevents request reuse |
| Time Bounds | created/expires limit validity window |
Binding Modes
Request-Bound (Required)
To be ERC-8128 compliant, implementations must support request-bound signatures. This mode signs everything relevant to the request:
@authority— Domain (prevents use on different server)@method— HTTP method (prevents GET→POST)@path— Path (prevents use on different endpoint)@query— Query string (if present)content-digest— Body hash (if body present)
Request-bound provides full request integrity. The request sender can always choose this strictest option for maximum security.
Class-Bound (Optional)
A class-bound signature authorizes a class of requests rather than a single concrete request. It signs only specified components, so a single signature can apply to any request matching those components:
- A signature covering only
@authorityworks for any endpoint on that domain - Reduces signing and verification overhead for high-frequency, low-risk operations
- Enables broad authorization patterns (e.g., "any GET on this API")
The signer chooses to produce a class-bound signature, but the verifier decides whether to accept it. By default, verifiers reject class-bound signatures — they must explicitly opt in via classBoundPolicies. See Request Binding for details.
Signature Selection Priority
When multiple signatures are present on a request, the verifier evaluates them in priority order:
- Request-bound signatures are tried first (strongest security)
- Class-bound signatures are tried in order of policy specificity (fewer required components = less restrictive = tried first)
- Header order breaks ties within the same priority tier
This ensures the most specific authorization is accepted when available, while still allowing broader authorizations when explicitly configured.
Replay Protection
Two modes, chosen by the signer:
| Mode | Nonce | Properties |
|---|---|---|
non-replayable | Required | Single-use authorization. Verifier must track nonces. |
replayable | Omitted | Reusable within validity window. No nonce state needed. Verifier must implement early invalidation. |
Non-replayable is the baseline — all compliant verifiers must accept it. Replayable acceptance is optional and up to the verifier.
The verifier can define different security profiles on a per-endpoint or per-request basis. For example, critical endpoints (like /transfer or /admin) may require request-bound, non-replayable signatures for maximum security, while read-only or low-risk endpoints (like /balance or /profile) could accept class-bound or replayable signatures for better performance.
See Replay Protection for the full tradeoff analysis.
Account Types
| Account Type | Signature | Verification |
|---|---|---|
| EOA | ECDSA (65 bytes) | ecrecover |
| SCA | Contract-defined | ERC-1271 isValidSignature |
Both are supported transparently — the verifier checks if the address is a contract and uses the appropriate method.
Why RFC 9421?
RFC 9421 (HTTP Message Signatures) is an IETF standard that provides:
- Canonical serialization of HTTP components
- Extensible component system
- Multi-signature support
- Time bounds and nonce support
ERC-8128 is a profile of RFC 9421 with Ethereum-specific defaults.
Next Steps
- Request Binding — Deep dive into what gets signed
- Replay Protection — Nonce handling details
- Security Model — Threat model and mitigations