Skip to Content
ConceptsDelegation

Delegation

The problem

Your agent has an identity. But identity alone doesn’t answer the question: “What is this agent allowed to do?”

An agent claiming to be from acme.com might have full admin access, or it might only be allowed to read emails. Without a way to express and verify permissions, services have to either trust everything or block everything.

How Credat solves it

A delegation is a cryptographically signed permission slip from an owner to an agent.

It says: “I (the owner) authorize this agent to do X, Y, and Z, until this date, under these constraints.”

import { delegate } from "@credat/sdk"; const delegation = await delegate({ agent: "did:web:acme.com:agent-1", owner: "did:web:acme.com", ownerKeyPair: ownerKeyPair, scopes: ["email:read", "email:send"], constraints: { allowedDomains: ["gmail.com"], maxTransactionValue: 1000, }, validUntil: "2026-06-01T00:00:00Z", });

The resulting credential (delegation.token) is an SD-JWT VC --- a compact, signed token that the agent can present to any service.

What’s in a delegation?

FieldPurpose
agentDID of the agent receiving the delegation
ownerDID of the owner granting it
scopesArray of permission strings (e.g. ["files:read", "api:call"])
constraintsOptional limits (domains, transaction values, rate limits)
validFromWhen the delegation becomes active (ISO 8601)
validUntilWhen it expires (ISO 8601)

Verification

Any service can verify a delegation with just the owner’s public key:

import { verifyDelegation } from "@credat/sdk"; const result = await verifyDelegation(delegation.token, { ownerPublicKey: ownerKeyPair.publicKey, }); if (result.valid) { console.log(result.scopes); // ["email:read", "email:send"] console.log(result.constraints); // { allowedDomains: ["gmail.com"], ... } } else { console.log(result.errors); // What went wrong }

Verification checks:

  1. Signature --- Was this really signed by the owner?
  2. Expiration --- Is the delegation still valid?
  3. Revocation --- Has the owner revoked it? (optional)

Constraints

Constraints are typed common fields plus an open escape hatch for custom data.

Built-in constraint fields

FieldTypeMeaning
maxTransactionValuenumberMaximum value per transaction
validUntilstringExpiration (ISO 8601)
allowedDomainsstring[]Domains the agent can interact with
rateLimitnumberMax operations per time period

Custom constraints

You can add any key-value pair:

const delegation = await delegate({ // ... constraints: { allowedDomains: ["api.stripe.com"], maxTransactionValue: 500, // Custom constraints environment: "production", team: "engineering", }, });

Important: Credat includes constraints in the credential but does not enforce them. Enforcement is your application’s job. Credat gives you the data; you write the rules.

Selective disclosure

Scopes and constraints use selective disclosure by default. The agent can choose which scopes to reveal when presenting the credential:

  • An agent with ["email:read", "email:send", "files:admin"] can present only ["email:read"] to a service that only needs email access.
  • Constraints can be selectively disclosed the same way.

This is privacy-preserving: the agent doesn’t have to reveal all its permissions to every service.

Revocation

Delegations can be revoked using status lists:

const delegation = await delegate({ // ... statusList: { url: "https://acme.com/.well-known/status-list.json", index: 42 }, });

The owner can later flip bit 42 in the status list to revoke this specific delegation without affecting others. See the API reference for details.

Last updated on