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
- Verify Delegation Chains: Always verify delegation chains when accepting delegated credentials
- Limit Delegation Scope: Only delegate necessary capabilities
- Monitor Delegation: Regularly audit delegation relationships
- Document Delegation: Keep records of why delegations were granted
- 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
- Resolve delegator DID document
- Check if
capabilityDelegationlist contains delegate - Resolve delegate DID document
- Verify delegate exists and is valid
- (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
capabilityDelegationrelationships - Delegate not in list: Delegate is not in delegator’s
capabilityDelegationlist - Broken chain: One link in multi-hop chain is invalid