Delegated principals
The delegated extension carries a recursive chain of signed EIP-712
Delegation values. The initial issuer becomes the authenticated principal; the leaf
delegate is the request signer.
const prepared = buildDelegationGrant({
issuer,
delegate,
audiences: ["https://api.example"],
id,
epoch,
validUntil,
maxRequestValiditySeconds: 60,
delegateIsEOA: true,
requireNonReplayable: true,
requiredComponents: [],
permissions: ["orders:read"]
})
const link = completeDelegationGrant(
prepared,
await rootSigner.signTypedData(prepared.typedData)
)
const chain = createDelegationChain([link])
const session = createDelegatedSignerClient(delegateSigner, chain)
const request = await session.signRequest("https://api.example/orders")
const result = await verifyRequest({
request,
nonceStore,
verifyMessage,
verifyDigest,
policy: {
principal: "delegated",
delegation: {
requiredPermissions: ["orders:read"],
permissionsSupported: true,
verifyStatuses: (contexts) =>
readCanonicalStatuses(contexts.map(({ link }) => link.grant))
}
}
})The wire request contains:
ERC-8128-Delegation: g0=:...:(andg1, etc. for recursive chains);- one
Signature-Inputmember taggederc8128-delegatedwhosekeyidis the leaf delegate and which covers"erc-8128-delegation";sf; - the matching one
Signaturemember.
There is no separate RFC 9421 root, authorization, or grant signature. The EIP-712 proof is the final element of each deterministic-CBOR link. The compact wire encoding does not change the signed EIP-712 grant or its digest.
Every child grant names its parent digest and must narrow the inherited
audiences, validity, maximum request validity, single-use posture, required
components, and permissions. The
verifier resolves these effective constraints for arbitrary supported depth,
verifies request proof before grant proofs, checks every link's canonical
(issuer chain, issuer, id, epoch) status through one batch hook, and consumes
a leaf nonce only after permission checks succeed. Registry-backed
implementations should group links by issuer chain and resolve each group with
one multicall per configured RPC/quorum client.
Positive proof caches are keyed by the EIP-712 digest and exact signature bytes.
Audience, time, attenuation, permissions, and revocation remain per-request
checks. grantCacheTtlSec defaults to 60 seconds and bounds how long an SCA
state change can remain hidden by a cached positive proof; deployments must
document that policy. Set it to 0 to bypass proof-cache reads and writes. Use
{ nonce: null } only when every link sets
requireNonReplayable=false and the destination verifier accepts
Replayable requests.