Types
Glossary of types in @slicekit/erc8128.
Hex
Hex-encoded string with 0x prefix.
type Hex = `0x${string}`Address
Ethereum address (40 hex characters with 0x prefix).
type Address = `0x${string}`EthHttpSigner
Interface for Ethereum message signing. Used by signRequest and signedFetch.
interface EthHttpSigner {
/** Ethereum address (EOA or smart contract account) */
address: Address
/** Chain ID for the keyid */
chainId: number
/** Sign the RFC 9421 signature base as an Ethereum message (EIP-191) */
signMessage: (message: Uint8Array) => Promise<Hex>
}Example
Here's how to create an EthHttpSigner using viem's privateKeyToAccount:
import type { EthHttpSigner } from '@slicekit/erc8128'
import { privateKeyToAccount } from 'viem/accounts'
const account = privateKeyToAccount('0x...')
const signer: EthHttpSigner = {
chainId: 1,
address: account.address,
signMessage: async (message) => {
return account.signMessage({ message: { raw: message } })
},
}SignOptions
Options for signRequest and signedFetch.
type SignOptions = {
/** Signature label (default: "eth") */
label?: string
/** Binding mode (default: "request-bound") */
binding?: BindingMode
/** Replay mode (default: "non-replayable") */
replay?: ReplayMode
/** Unix timestamp when signature becomes valid (default: now) */
created?: number
/** Unix timestamp when signature expires (default: created + ttlSeconds) */
expires?: number
/** Validity duration in seconds (default: 60) */
ttlSeconds?: number
/** Custom nonce value or generator function */
nonce?: string | (() => Promise<string>)
/** Content-Digest handling (default: "auto") */
contentDigest?: ContentDigestMode
/** Additional components to sign beyond the default set */
components?: string[]
}BindingMode
Controls which request components are signed.
type BindingMode = "request-bound" | "class-bound"| Value | Description |
|---|---|
request-bound | Sign @authority, @method, @path, @query (if present), and content-digest (if body present). This is the secure default. |
class-bound | Sign only the components you explicitly specify. Requires components array. |
ReplayMode
Controls whether requests can be replayed.
type ReplayMode = "non-replayable" | "replayable"| Value | Description |
|---|---|
non-replayable | Include a nonce (auto-generated if not provided). Default. |
replayable | No nonce. Signature can be reused within its validity window. Trades single-use guarantee for reduced overhead. |
ContentDigestMode
Controls Content-Digest header handling.
type ContentDigestMode = "auto" | "recompute" | "require" | "off"| Value | Description |
|---|---|
auto | Add Content-Digest if body is present and components include it. Default. |
recompute | Always recompute Content-Digest even if header exists. |
require | Require existing Content-Digest header. |
off | Don't add Content-Digest. |
VerifyPolicy
Policy for verifyRequest.
type VerifyPolicy = {
/** Preferred signature label (default: "eth") */
label?: string
/** If true, require exact label match (default: false) */
strictLabel?: boolean
/**
* Extra components required in addition to the default request-bound set.
* Use this for custom headers like 'x-idempotency-key'.
*/
additionalRequestBoundComponents?: string[]
/**
* Class-bound policies (one list or a list of lists).
* If any policy list is covered by the signed components, the signature is accepted.
* `@authority` is always required (added if missing).
*/
classBoundPolicies?: string[] | string[][]
/** Allow replayable (nonce-less) signatures (default: false) */
replayable?: boolean
/**
* Optional replayable invalidation (per-keyid).
* When set and a signature is replayable, requests with created < notBefore are rejected.
*/
replayableNotBefore?: (keyid: string) => number | null | undefined | Promise<number | null | undefined>
/**
* Optional per-signature invalidation hook for replayable signatures.
* Return true to mark the signature as invalidated.
*/
replayableInvalidated?: (args: {
keyid: string
created: number
expires: number
label: string
signature: Hex
signatureBase: Uint8Array
signatureParamsValue: string
}) => boolean | Promise<boolean>
/** Maximum number of signatures to verify (default: 3) */
maxSignatureVerifications?: number
/** Current time function (default: Date.now() / 1000) */
now?: () => number
/** Allowed clock skew in seconds (default: 0) */
clockSkewSec?: number
/** Maximum validity window in seconds (default: 300) */
maxValiditySec?: number
/** Maximum nonce validity window (optional) */
maxNonceWindowSec?: number
/** Custom key generator for nonce storage */
nonceKey?: (keyid: string, nonce: string) => string
}NonceStore
Interface for replay protection storage. See NonceStore implementations.
interface NonceStore {
/**
* Atomically consume a nonce.
* Returns true if newly stored (not seen before), false if already exists.
*/
consume(key: string, ttlSeconds: number): Promise<boolean>
}VerifyMessageFn
Function type for verifying Ethereum signatures. See VerifyMessageFn with viem.
type VerifyMessageFn = (args: {
address: Address
message: { raw: Hex }
signature: Hex
}) => boolean | Promise<boolean>VerifyResult
Result of verifyRequest.
type VerifyResult =
| {
ok: true
address: Address
chainId: number
label: string
components: string[]
params: SignatureParams
replayable: boolean
binding: BindingMode
}
| {
ok: false
reason: VerifyFailReason
detail?: string
}Success Properties
| Property | Type | Description |
|---|---|---|
ok | true | Verification succeeded |
address | Address | Verified Ethereum address |
chainId | number | Chain ID from keyid |
label | string | Signature label that was verified |
components | string[] | Components that were signed |
params | SignatureParams | Parsed signature parameters |
replayable | boolean | Whether the signature is replayable (nonce-less) |
binding | BindingMode | Binding mode used by the signature |
Failure Properties
| Property | Type | Description |
|---|---|---|
ok | false | Verification failed |
reason | VerifyFailReason | Why verification failed |
detail | string? | Optional detail message |
SignatureParams
Parsed signature parameters from Signature-Input header.
type SignatureParams = {
created: number
expires: number
keyid: string
nonce?: string
tag?: string
}VerifyFailReason
All possible verification failure reasons. See Failure Reasons for descriptions.
type VerifyFailReason =
| "missing_headers"
| "label_not_found"
| "bad_signature_input"
| "bad_signature"
| "bad_keyid"
| "bad_time"
| "not_yet_valid"
| "expired"
| "validity_too_long"
| "nonce_required"
| "replayable_not_allowed"
| "replayable_invalidation_required"
| "replayable_not_before"
| "replayable_invalidated"
| "class_bound_not_allowed"
| "nonce_window_too_long"
| "replay"
| "not_request_bound"
| "digest_required"
| "digest_mismatch"
| "alg_not_allowed"
| "bad_signature_bytes"
| "bad_signature_check"Client
Return type of createSignerClient. Provides bound methods for signing requests.
type Client = {
signRequest: {
(input: RequestInfo, opts?: SignOptions): Promise<Request>
(input: RequestInfo, init: RequestInit | undefined, opts?: SignOptions): Promise<Request>
}
signedFetch: {
(input: RequestInfo, opts?: ClientOptions): Promise<Response>
(input: RequestInfo, init: RequestInit | undefined, opts?: ClientOptions): Promise<Response>
}
fetch: {
(input: RequestInfo, opts?: ClientOptions): Promise<Response>
(input: RequestInfo, init: RequestInit | undefined, opts?: ClientOptions): Promise<Response>
}
}Methods
| Method | Description |
|---|---|
signRequest | Sign a request without sending |
signedFetch | Sign and send a request |
fetch | Alias for signedFetch |
ClientOptions
Options for createSignerClient and client methods. Extends SignOptions.
type ClientOptions = SignOptions & { fetch?: typeof fetch }VerifierClient
Return type of createVerifierClient. Provides a bound method for verifying requests.
type VerifierClient = {
verifyRequest: (args: {
request: Request
policy?: VerifyPolicy
setHeaders?: (name: string, value: string) => void
}) => Promise<VerifyResult>
}Methods
| Method | Description |
|---|---|
verifyRequest | Verify a signed request |
VerifierClientOptions
Options for createVerifierClient and client methods. Extends VerifyPolicy.
type VerifierClientOptions = VerifyPolicySetHeadersFn
Callback to set response headers. Used by verifyRequest to emit Accept-Signature.
type SetHeadersFn = (name: string, value: string) => voidVerifyRequestArgs
Argument object for verifyRequest.
type VerifyRequestArgs = {
request: Request
verifyMessage: VerifyMessageFn
nonceStore: NonceStore
policy?: VerifyPolicy
setHeaders?: SetHeadersFn
}| Property | Type | Description |
|---|---|---|
request | Request | The HTTP request to verify |
verifyMessage | VerifyMessageFn | Signature verification function |
nonceStore | NonceStore | Replay protection store |
policy | VerifyPolicy | Optional verification policy |
setHeaders | SetHeadersFn | Optional callback to set Accept-Signature response header |
VerifierClientVerifyRequestArgs
Argument object for verifierClient.verifyRequest(). The client already has verifyMessage and nonceStore bound, so only request and optional overrides are needed.
type VerifierClientVerifyRequestArgs = {
request: Request
policy?: VerifyPolicy
setHeaders?: SetHeadersFn
}CreateVerifierClientArgs
Argument object for createVerifierClient.
type CreateVerifierClientArgs = {
verifyMessage: VerifyMessageFn
nonceStore: NonceStore
defaults?: VerifyPolicy
}| Property | Type | Description |
|---|---|---|
verifyMessage | VerifyMessageFn | Signature verification function |
nonceStore | NonceStore | Replay protection store |
defaults | VerifyPolicy | Default policy applied to all requests |
Erc8128Error
Custom error class for ERC-8128 operations.
class Erc8128Error extends Error {
code: Erc8128ErrorCode
}Erc8128ErrorCode
Error codes for Erc8128Error.
type Erc8128ErrorCode =
| "CRYPTO_UNAVAILABLE" // WebCrypto not available
| "INVALID_OPTIONS" // Bad sign options
| "UNSUPPORTED_REQUEST" // Can't sign this request
| "BODY_READ_FAILED" // Can't read request body
| "DIGEST_REQUIRED" // Content-Digest required but not present
| "BAD_DERIVED_VALUE" // Can't derive component value
| "BAD_HEADER_VALUE" // Invalid header format
| "PARSE_ERROR" // Can't parse inputExample
Catch Erc8128Error to handle specific error codes during signing or verification:
import { signRequest, Erc8128Error } from '@slicekit/erc8128'
try {
const signedRequest = await signRequest(input, signer)
} catch (error) {
if (error instanceof Erc8128Error) {
console.error(`Error (${error.code}): ${error.message}`)
}
throw error
}