Delegation

Overview

Delegation allows a DID (delegator) to grant capabilities to another DID (delegate). This enables hierarchical authority structures where DIDs can delegate credential issuance or other capabilities to subordinate DIDs.

Delegation is essential for:

  • Corporate hierarchies: CEOs delegating to departments
  • Government structures: Agencies delegating to regional offices
  • Educational institutions: Universities delegating to departments
  • Service providers: Main providers delegating to sub-providers

Key Concepts

Capability Delegation

Capability Delegation is a verification relationship in a DID Document that indicates which verification methods can be used to delegate capabilities to other DIDs. When a DID includes another DID’s verification method in its capabilityDelegation list, it grants that DID the authority to perform operations on its behalf.

Capability Invocation

Capability Invocation is a verification relationship that indicates which verification methods can be used to invoke capabilities on behalf of the DID. This is typically used for:

  • Signing documents
  • Performing actions
  • Invoking services
  • Executing operations

Delegation Chain

A delegation chain is a sequence of DIDs where each DID delegates authority to the next, forming a hierarchical structure. For example:

  • CEO → HR Director → HR Manager → HR Assistant

Each link in the chain must be verified to ensure the entire delegation is valid.

Usage

Setting Up Delegation

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import org.trustweave.trust.dsl.credential.DidMethods
// Step 1: Update delegator DID document to include capability delegation
trustWeave.updateDid {
    did(delegatorDid)
    method(DidMethods.KEY)
    addCapabilityDelegation("$delegateDid#key-1")
}.update()

// Step 2: Verify the delegation was set up correctly
val delegationResult = trustWeave.delegate {
    from(delegatorDid)
    to(delegateDid)
    verify()
}

if (delegationResult.valid) {
    println("Delegation set up successfully")
}

Verifying Delegation Chain

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// Note: DelegationBuilder has no capability() filter; the chain verifier walks
// capabilityDelegation references in the resolved DID documents.
val result = trustWeave.delegate {
    from(delegatorDid)
    to(delegateDid)
    verify()
}

if (result.valid) {
    println("Delegation verified:")
    println("  Path: ${result.path.joinToString(" -> ")}")
} else {
    println("Delegation failed:")
    result.errors.forEach { println("  - $it") }
}

Multi-Hop Delegation

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import org.trustweave.trust.dsl.credential.DidMethods
// Set up multi-hop delegation chain
trustWeave.updateDid {
    did(ceoDid)
    method(DidMethods.KEY)
    addCapabilityDelegation("$directorDid#key-1")
}.update()

trustWeave.updateDid {
    did(directorDid)
    method(DidMethods.KEY)
    addCapabilityDelegation("$managerDid#key-1")
}.update()

// Verify the entire chain (verifyChain accepts a List<String> of DIDs)
val result = trustWeave.delegate {
    verifyChain(listOf(ceoDid, directorDid, managerDid))
}

if (result.valid) {
    println("Full delegation chain verified: ${result.path.joinToString(" -> ")}")
}

Using Delegated Credentials

When a credential is issued by a delegate, the verification can check the delegation chain:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
import kotlinx.datetime.Clock
import org.trustweave.trust.types.delegationValid
import org.trustweave.did.identifiers.Did

// Issue credential using delegated authority (delegateDid / employeeDid: String DIDs from your setup)
val credential = trustWeave.issue {
    credential {
        id("https://company.com/credential-123")
        type("EmploymentCredential")
        issuer(delegateDid)
        subject {
            id(employeeDid)
            "employment" {
                "company" to "Tech Corp"
                "role" to "Software Engineer"
            }
        }
        issued(Clock.System.now())
    }
    signedBy(issuerDid = Did(delegateDid), keyId = "key-1")
}.getOrThrow()

// Verify credential and separately verify the delegation chain
val result = trustWeave.verify {
    credential(credential)
    checkExpiration()
}

// VerificationBuilder does not have a dedicated verifyDelegation() method;
// trigger the delegation walk explicitly via trustWeave.delegate { ... }.
val delegation = trustWeave.delegate {
    verifyChain(listOf(rootDid, delegateDid))
}

if (delegation.valid && result.delegationValid) {
    println("Delegation chain is valid")
} else {
    println("Delegation verification failed: ${result.allErrors.joinToString()}")
}

Verification Relationships

Capability Delegation

Used when a DID grants authority to another DID. The delegate can then use this authority to perform operations.

Example: A CEO delegates credential issuance to an HR Director.

1
2
3
4
trustWeave.updateDid {
    did(ceoDid)
    addCapabilityDelegation("$hrDirectorDid#key-1")
}

Capability Invocation

Used when a DID invokes capabilities on its own behalf. This is typically used for signing documents or performing actions.

Example: An employee signs a document using their capability invocation key.

1
2
3
4
trustWeave.updateDid {
    did(employeeDid)
    addCapabilityInvocation("$employeeDid#key-1")
}

Example: Corporate Hierarchy

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
import kotlinx.coroutines.runBlocking
import kotlinx.datetime.Clock
import org.trustweave.credential.results.VerificationResult
import org.trustweave.did.identifiers.Did
import org.trustweave.trust.TrustWeave
import org.trustweave.trust.dsl.credential.DidMethods
import org.trustweave.trust.dsl.credential.KeyAlgorithms
import org.trustweave.trust.dsl.credential.KmsProviders
import org.trustweave.trust.types.delegationValid
import org.trustweave.trust.types.proofValid
import org.trustweave.trust.types.getOrThrowDid

runBlocking {
    // Step 1: Create DIDs for corporate hierarchy
    val trustWeave = TrustWeave.build {
        keys { provider(KmsProviders.IN_MEMORY); algorithm(KeyAlgorithms.ED25519) }
        did { method(DidMethods.KEY) { algorithm(KeyAlgorithms.ED25519) } }
    }

    val ceoDid = trustWeave.createDid { method(DidMethods.KEY) }.getOrThrowDid().value
    val hrDirectorDid = trustWeave.createDid { method(DidMethods.KEY) }.getOrThrowDid().value
    val hrManagerDid = trustWeave.createDid { method(DidMethods.KEY) }.getOrThrowDid().value
    val employeeDid = trustWeave.createDid { method(DidMethods.KEY) }.getOrThrowDid().value

    // Step 2: Set up delegation chain
    trustWeave.updateDid {
        did(ceoDid)
        method(DidMethods.KEY)
        addCapabilityDelegation("$hrDirectorDid#key-1")
    }.update()

    trustWeave.updateDid {
        did(hrDirectorDid)
        method(DidMethods.KEY)
        addCapabilityDelegation("$hrManagerDid#key-1")
    }.update()

    // Step 3: Verify the full chain
    val result = trustWeave.delegate {
        verifyChain(listOf(ceoDid, hrDirectorDid, hrManagerDid))
    }

    if (result.valid) {
        println("Corporate delegation chain verified:")
        println("  ${result.path.joinToString(" -> ")}")
    } else {
        println("Delegation chain verification failed:")
        result.errors.forEach { println("  - $it") }
    }

    // Step 4: Issue credential using delegated authority
    val credential = trustWeave.issue {
        credential {
            id("https://company.com/credential-123")
            type("EmploymentCredential")
            issuer(hrManagerDid)
            subject {
                id(employeeDid)
                "employment" {
                    "company" to "Tech Corp"
                    "role" to "Software Engineer"
                    "startDate" to "2024-01-01"
                }
            }
            issued(Clock.System.now())
        }
        signedBy(issuerDid = Did(hrManagerDid), keyId = "key-1")
    }.getOrThrow()

    // Step 5: Verify the credential, then walk the delegation chain separately
    val verification = trustWeave.verify {
        credential(credential)
        checkExpiration()
    }

    println("Credential Verification:")
    println("  Valid: ${verification is VerificationResult.Valid}")
    println("  Delegation valid: ${verification.delegationValid}")
    println("  Proof valid: ${verification.proofValid}")
}

Advanced Usage

Removing Delegation

1
2
3
4
5
6
import org.trustweave.trust.dsl.credential.DidMethods
trustWeave.updateDid {
    did(delegatorDid)
    method(DidMethods.KEY)
    removeCapabilityDelegation("$delegateDid#key-1")
}

Multiple Delegates

A delegator can delegate to multiple DIDs:

1
2
3
4
5
6
7
8
import org.trustweave.trust.dsl.credential.DidMethods
trustWeave.updateDid {
    did(ceoDid)
    method(DidMethods.KEY)
    addCapabilityDelegation("$hrDirectorDid#key-1")
    addCapabilityDelegation("$financeDirectorDid#key-1")
    addCapabilityDelegation("$itDirectorDid#key-1")
}

Self-Delegation

A DID can delegate to itself (useful for key rotation):

1
2
3
4
5
6
import org.trustweave.trust.dsl.credential.DidMethods
trustWeave.updateDid {
    did(did)
    method(DidMethods.KEY)
    addCapabilityDelegation("$did#key-2") // Delegate to new key
}

Best Practices

  1. Verify Delegation Chains: Always verify delegation chains when accepting delegated credentials
  2. Limit Delegation Scope: Only delegate necessary capabilities
  3. Monitor Delegation: Regularly audit delegation relationships
  4. Document Delegation: Keep records of why delegations were granted
  5. Revoke When Needed: Remove delegations when they’re no longer needed

Implementation Details

Delegation Service

The DelegationService:

  • Verifies single-hop delegation chains
  • Supports multi-hop delegation verification
  • Validates capability delegation relationships in DID Documents
  • Returns detailed error messages for failed verifications

Verification Process

  1. Resolve delegator DID document
  2. Check if capabilityDelegation list contains delegate
  3. Resolve delegate DID document
  4. Verify delegate exists and is valid
  5. (Future) Verify delegation credential/proof if present

Error Handling

Common delegation verification errors:

  • Delegator not found: Delegator DID cannot be resolved
  • Delegate not found: Delegate DID cannot be resolved
  • No capability delegation: Delegator has no capabilityDelegation relationships
  • Delegate not in list: Delegate is not in delegator’s capabilityDelegation list
  • Broken chain: One link in multi-hop chain is invalid

See Also


This site uses Just the Docs, a documentation theme for Jekyll.