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

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=:...: (and g1, etc. for recursive chains);
  • one Signature-Input member tagged erc8128-delegated whose keyid is the leaf delegate and which covers "erc-8128-delegation";sf;
  • the matching one Signature member.

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.