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: "request") */
label?: string
/** Binding mode (default: "request-bound") */
binding?: BindingMode
/** Unix timestamp when signature becomes valid (default: now) */
created?: number
/** Unix timestamp when signature expires (default: created + ttlSeconds) */
expires?: number
/** Library default: 60; prefer the shortest delivery-safe duration. */
ttlSeconds?: number
/** Custom nonce/generator, or null to make the request Replayable */
nonce?: string | (() => Promise<string>) | null
/** 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 @scheme, @authority, @method, @path, and @query unconditionally, plus received content fields. This is the secure default. |
class-bound | Sign only the components you explicitly specify. Requires components array. |
ReplayMode
Describes the replay posture returned by verification. Signing infers this
posture solely from nonce presence: the default generated nonce is
Non-Replayable and { nonce: null } is Replayable.
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 | Disable automatic digest handling. Signing throws if covered components require content-digest. |
VerifyPolicy
Policy for verifyRequest.
type VerifyPolicy = {
/** Select base-profile (`direct`), delegated, or either principal class. */
principal?: "direct" | "delegated" | "either"
/** Base-profile account verification policy (default: "universal"). */
accountVerification?: "universal" | "eoa-only"
/**
* Extra components required in addition to the default request-bound set.
* Use this for custom headers like 'x-idempotency-key'.
*/
additionalRequestBoundComponents?: string[]
/** Require these request headers to be covered whenever they are present. */
requiredCoveredHeadersWhenPresent?: 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).
* An empty list disables class-bound acceptance.
*/
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
signature: Hex
}) => boolean | Promise<boolean>
/** Maximum number of request-signature candidates to verify (default: 8) */
maxSignatureVerifications?: number
/**
* Universal Account classification/proof calls shared across candidates.
* Defaults to 2 + the configured delegation-chain depth.
*/
maxAccountVerificationCalls?: 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. The key must derive only from
* covered signature material, and all verifier backends must share one
* logical nonce namespace.
*/
nonceKey?: (keyid: string, nonce: string) => string
/** Required to accept delegated signatures. */
delegation?: DelegationPolicy
}type DelegationPolicy = {
grantCache?: DelegationGrantCache
/** Default 60 seconds; 0 bypasses proof-cache reads and writes. */
grantCacheTtlSec?: number
maxChainDepth?: number
maxGrantValiditySec?: number
requiredPermissions?: readonly string[]
permissionsSupported?: boolean
verifyStatuses: (
contexts: readonly DelegationStatusContext[]
) =>
| readonly DelegationStatus[]
| Promise<readonly DelegationStatus[]>
}Positive grant-proof caches are keyed by the grant digest and signature bytes. DelegationGrantCache.set receives an absolute Unix expiry, and get must not return the entry once that expiry has passed. Deployments must document how the configured TTL bounds stale acceptance after an SCA state change.
verifyStatuses receives every ordered link in the resolved chain at once and
returns one status in the same order. This lets registry-backed verifiers use a
single multicall rather than one RPC request per link. Registry chain and
address are not grant fields or ordinary signer configuration.
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
chainId: number
message: { raw: Hex }
signature: Hex
}) => boolean | 'unavailable' | Promise<boolean | 'unavailable'>createUniversalAccountVerifier({ getCode, verifySmartAccount }) constructs
this function with ERC-6492-first verification, ERC-1271 for code-bearing
accounts, and strict local recovery for code-free EOAs. RPC failures return
"unavailable".
VerifyResult
Result of verifyRequest.
type VerifyResult =
| {
ok: true
principal: { address: Address; chainId: number }
signer: { address: Address; chainId: number }
delegated: false
label: string
components: ComponentIdentifier[]
params: SignatureParams
replay: ReplayMode
binding: BindingMode
}
| {
ok: true
principal: { address: Address; chainId: number }
signer: { address: Address; chainId: number }
delegated: true
delegationIds: Hex[]
replay: ReplayMode
binding: BindingMode
}
| {
ok: false
reason: VerifyFailReason
detail?: string
}Success Properties
| Property | Type | Description |
|---|---|---|
ok | true | Verification succeeded |
principal | AccountIdentity | Authenticated root or base-profile account |
signer | AccountIdentity | Account that signed the request |
delegated | boolean | Whether a delegation authorization authenticated the principal |
delegationIds | Hex[] | Ordered signed revocation IDs for the verified chain |
label | string | Signature label that was verified |
components | ComponentIdentifier[] | Structurally parsed signed components |
params | SignatureParams | Parsed signature parameters |
replay | ReplayMode | Whether the signature is replayable or non-replayable |
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 =
| "signature_missing"
| "no_acceptable_signature"
| "signature_input_invalid"
| "signature_too_large"
| "invalid_keyid"
| "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"
| "unsupported_delegation"
| "bad_delegation_field"
| "delegation_too_large"
| "delegation_not_covered"
| "delegate_mismatch"
| "delegation_chain_too_long"
| "delegation_chain_discontinuous"
| "delegation_attenuation_violation"
| "grant_expired"
| "grant_not_yet_valid"
| "grant_validity_too_long"
| "request_outside_grant_window"
| "bad_grant_signature"
| "audience_mismatch"
| "delegation_nonce_required"
| "delegation_request_validity_exceeded"
| "delegation_components_unsupported"
| "delegation_components_uncovered"
| "unsupported_permissions"
| "insufficient_permissions"
| "authorization_revoked"
| "authorization_epoch_mismatch"
| "grant_verification_unavailable"
| "revocation_unavailable"SignerClient
Return type of createSignerClient. Provides bound methods for signing requests.
type SignerClient = {
signRequest: {
(input: RequestInfo, opts?: SignOptions): Promise<Request>
(input: RequestInfo, init: RequestInit | undefined, opts?: SignOptions): Promise<Request>
}
signedFetch: {
(input: RequestInfo, opts?: FetchOptions): Promise<Response>
(input: RequestInfo, init: RequestInit | undefined, opts?: FetchOptions): Promise<Response>
}
fetch: {
(input: RequestInfo, opts?: FetchOptions): Promise<Response>
(input: RequestInfo, init: RequestInit | undefined, opts?: FetchOptions): Promise<Response>
}
setServerConfig: (origin: string, config: ServerConfig | null) => void
}Methods
| Method | Description |
|---|---|
signRequest | Sign a request without sending |
signedFetch | Sign and send a request |
fetch | Alias for signedFetch |
setServerConfig | Set or remove per-origin discovery config |
FetchOptions
Per-call options for client.fetch() and client.signedFetch(). Extends SignOptions with an optional fetch implementation override.
type FetchOptions = SignOptions & { fetch?: typeof fetch }SignerClientOptions
Options for createSignerClient.
type SignerClientOptions = SignOptions & {
fetch?: typeof fetch
serverConfigs?: Record<string, ServerConfig>
preferReplayable?: boolean
}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 with one canonical signature shape per supported policy.
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
}