Skip to content

Commit bc8dae2

Browse files
authored
Testing PEX proof requets with delegation (#446)
* testing proof requests with delegation * remove commented code * fixing merge issues * function to checkPresentationHolder * updating tests and adding documentation * add cedar reference * updating doc * fixing tests
1 parent 550ed09 commit bc8dae2

File tree

3 files changed

+594
-168
lines changed

3 files changed

+594
-168
lines changed

docs/delegation.md

Lines changed: 351 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,351 @@
1+
# Delegatable Credentials
2+
3+
Delegatable credentials enable a credential issuer (delegator) to delegate their authority to issue specific types of credentials to other entities (delegees). This creates a chain of trust where delegees can issue credentials on behalf of the original issuer, within the bounds of their delegated authority.
4+
5+
## Overview
6+
7+
A delegatable credential allows an issuer to:
8+
- Grant specific issuance authorities to delegates
9+
- Control which claims delegates can issue
10+
- Establish delegation chains with multiple levels
11+
- Enforce policies using Cedar policy language
12+
- Verify the entire delegation chain during presentation
13+
14+
## Key Concepts
15+
16+
### Delegation Chain
17+
18+
A delegation chain consists of:
19+
- **Root Credential**: The original delegation issued by the authoritative issuer
20+
- **Delegated Credentials**: Credentials issued by delegates using their delegated authority
21+
- **Chain Verification**: Each credential in the chain references its predecessor via `previousCredentialId` and the root via `rootCredentialId`
22+
23+
### May Claim
24+
25+
The `mayClaim` property (IRI: `https://www.dock.io/rdf2020#mayClaim`) specifies which claims a delegate is authorized to issue. For example:
26+
27+
```javascript
28+
credentialSubject: {
29+
id: 'did:example:delegate',
30+
creditScore: 760,
31+
[MAY_CLAIM_IRI]: ['creditScore'], // Delegate can only issue creditScore claims
32+
}
33+
```
34+
35+
### Cedar Policies
36+
37+
[Cedar](https://docs.cedarpolicy.com/) is a language for defining permissions as policies. Cedar policies provide fine-grained authorization control over delegation chains. They can enforce:
38+
- Maximum delegation depth
39+
- Required root issuer
40+
- Minimum claim values
41+
- Specific claim values
42+
43+
## API Reference
44+
45+
### Core Functions
46+
47+
#### `issueDelegationCredential(keyDoc, options)`
48+
49+
Issues a root delegation credential that grants authority to a delegate.
50+
51+
**Parameters:**
52+
- `keyDoc`: Signing key document of the issuer
53+
- `options`:
54+
- `id`: Unique credential identifier
55+
- `issuer`: DID of the issuer
56+
- `@context`: JSON-LD context including delegation terms
57+
- `issuanceDate`: ISO timestamp
58+
- `type`: Array including 'DelegationCredential'
59+
- `credentialSubject`: Object containing:
60+
- `id`: DID of the delegate
61+
- `[MAY_CLAIM_IRI]`: Array of authorized claim names
62+
- Additional claims
63+
- `previousCredentialId`: Should be `null` for root credentials
64+
- `rootCredentialId`: Should be `null` for root credentials
65+
66+
**Returns:** Signed delegation credential
67+
68+
**Example:**
69+
```javascript
70+
const rootCredential = await issueDelegationCredential(issuerKey, {
71+
id: 'urn:uuid:12345678',
72+
issuer: issuerDid,
73+
'@context': CREDIT_SCORE_DELEGATION_CONTEXT,
74+
issuanceDate: new Date().toISOString(),
75+
type: [
76+
'VerifiableCredential',
77+
'CreditScoreCredential',
78+
'DelegationCredential',
79+
],
80+
credentialSubject: {
81+
id: holderDid,
82+
creditScore: 760,
83+
[MAY_CLAIM_IRI]: ['creditScore'],
84+
},
85+
previousCredentialId: null,
86+
rootCredentialId: null,
87+
});
88+
```
89+
90+
#### `issueDelegatedCredential(keyDoc, options)`
91+
92+
Issues a credential using delegated authority.
93+
94+
**Parameters:**
95+
- `keyDoc`: Signing key document of the delegate
96+
- `options`:
97+
- `id`: Unique credential identifier
98+
- `issuer`: DID of the delegate issuer
99+
- `@context`: JSON-LD context
100+
- `issuanceDate`: ISO timestamp
101+
- `type`: Array of credential types
102+
- `credentialSubject`: Object containing:
103+
- `id`: DID of the credential subject
104+
- Claims being issued
105+
- `[MAY_CLAIM_IRI]` (optional): For further delegation
106+
- `previousCredentialId`: ID of the delegating credential
107+
- `rootCredentialId`: ID of the root credential
108+
109+
**Returns:** Signed delegated credential
110+
111+
**Example:**
112+
```javascript
113+
const delegatedCredential = await issueDelegatedCredential(holderKey, {
114+
id: 'urn:uuid:87654321',
115+
issuer: holderDid,
116+
'@context': CREDIT_SCORE_CREDENTIAL_CONTEXT,
117+
issuanceDate: new Date().toISOString(),
118+
type: [
119+
'VerifiableCredential',
120+
'CreditScoreCredential',
121+
'DelegationCredential',
122+
],
123+
credentialSubject: {
124+
id: agentDid,
125+
creditScore: 400,
126+
[MAY_CLAIM_IRI]: ['creditScore'], // For further delegation
127+
},
128+
previousCredentialId: rootCredential.id,
129+
rootCredentialId: rootCredential.id,
130+
});
131+
```
132+
133+
#### `createSignedPresentation(keyDoc, options)`
134+
135+
Creates a signed verifiable presentation containing delegated credentials.
136+
137+
**Parameters:**
138+
- `keyDoc`: Signing key document of the holder
139+
- `options`:
140+
- `credentials`: Array of credentials (must include full delegation chain)
141+
- `holderDid`: DID of the presentation holder
142+
- `challenge`: Challenge string for replay protection
143+
- `domain`: Domain string for binding
144+
145+
**Returns:** Signed verifiable presentation
146+
147+
**Example:**
148+
```javascript
149+
const presentation = await createSignedPresentation(agentKey, {
150+
credentials: [rootCredential, credDelegatedToAgent],
151+
holderDid: agentDid,
152+
challenge: 'test-challenge-123',
153+
domain: 'test.example.com',
154+
});
155+
```
156+
157+
#### `verifyDelegatablePresentation(presentation, options)`
158+
159+
Verifies a presentation containing delegated credentials.
160+
161+
**Parameters:**
162+
- `presentation`: The verifiable presentation to verify
163+
- `options`:
164+
- `challenge`: Expected challenge string
165+
- `domain`: Expected domain string
166+
- `policies` (optional): Cedar policies object
167+
168+
**Returns:** Verification result object containing:
169+
- `verified`: Boolean indicating overall verification status
170+
- `delegationResult`: Delegation verification result with:
171+
- `decision`: 'allow' or 'deny'
172+
- `summaries`: Array of delegation chain summaries
173+
- `failures`: Array of failure objects (if denied)
174+
- `credentialResults`: Array of individual credential verification results
175+
176+
**Example:**
177+
```javascript
178+
const result = await verifyDelegatablePresentation(presentation, {
179+
challenge: CHALLENGE,
180+
domain: DOMAIN,
181+
policies,
182+
});
183+
184+
console.log('Verified:', result.verified);
185+
console.log('Decision:', result.delegationResult?.decision);
186+
```
187+
188+
#### `createCedarPolicy(options)`
189+
190+
Creates Cedar policy rules for delegation authorization.
191+
192+
**Parameters:**
193+
- `options`:
194+
- `maxDepth`: Maximum allowed delegation chain depth
195+
- `rootIssuer`: Required DID of the root issuer
196+
- `requiredClaims`: Object mapping claim names to required values:
197+
- Number values: minimum required value (e.g., `creditScore: 500`)
198+
- String values: exact required value (e.g., `role: "admin"`)
199+
- Any value: description of the claim requirement
200+
201+
**Returns:** Policy object with `staticPolicies` string
202+
203+
**Example:**
204+
```javascript
205+
const policies = createCedarPolicy({
206+
maxDepth: 2,
207+
rootIssuer: 'did:example:root-issuer',
208+
requiredClaims: {
209+
creditScore: 500, // Minimum value
210+
role: 'admin', // Exact match
211+
body: 'Issuer of Credits', // Description
212+
},
213+
});
214+
```
215+
216+
### Context Constants
217+
218+
#### `MAY_CLAIM_IRI`
219+
The IRI used for the `mayClaim` property in credential subjects.
220+
```javascript
221+
const MAY_CLAIM_IRI = 'https://www.dock.io/rdf2020#mayClaim';
222+
```
223+
224+
#### `DELEGATION_CONTEXT_TERMS`
225+
Base JSON-LD terms for delegation credentials.
226+
227+
#### `W3C_CREDENTIALS_V1`
228+
Standard W3C Verifiable Credentials context URL.
229+
230+
231+
## Integration with Presentation Exchange (PEX)
232+
233+
Delegatable credentials can be used with Presentation Exchange to request specific delegation chains:
234+
235+
```javascript
236+
const presentationDefinition = {
237+
id: 'delegation_test',
238+
input_descriptors: [
239+
{
240+
id: 'root-credential',
241+
name: 'Root Credential',
242+
purpose: 'Must be the root credential issued by the required issuer',
243+
group: ['1'],
244+
constraints: {
245+
fields: [
246+
{
247+
path: ['$.type'],
248+
filter: {
249+
type: 'array',
250+
contains: { const: 'CreditScoreCredential' },
251+
},
252+
},
253+
{
254+
path: ['$.issuer', '$.iss'],
255+
filter: {
256+
type: 'string',
257+
const: issuerDid,
258+
},
259+
},
260+
],
261+
},
262+
},
263+
{
264+
id: 'other-credentials',
265+
name: 'Additional Credentials',
266+
purpose: 'Any number of additional credentials of the specified type',
267+
group: ['2'],
268+
constraints: {
269+
fields: [
270+
{
271+
path: ['$.type'],
272+
filter: {
273+
type: 'array',
274+
contains: { const: 'CreditScoreCredential' },
275+
},
276+
},
277+
],
278+
},
279+
},
280+
],
281+
submission_requirements: [
282+
{
283+
from: '1',
284+
name: 'Root Credential',
285+
rule: 'pick',
286+
count: 1,
287+
},
288+
{
289+
from: '2',
290+
name: 'Additional Credentials',
291+
rule: 'pick',
292+
min: 0,
293+
},
294+
],
295+
};
296+
297+
// Filter credentials that match the definition
298+
const filterResult = await credentialService.filterCredentials({
299+
credentials: [rootCredential, credDelegatedToAgent],
300+
presentationDefinition,
301+
holderDid: agentDid,
302+
});
303+
304+
// Create presentation
305+
const presentation = await createSignedPresentation(agentKey, {
306+
credentials: [rootCredential, credDelegatedToAgent],
307+
holderDid: agentDid,
308+
challenge: CHALLENGE,
309+
domain: DOMAIN,
310+
});
311+
312+
// Evaluate presentation against definition
313+
const validationResults = await pexService.evaluatePresentation({
314+
presentation,
315+
presentationDefinition,
316+
});
317+
```
318+
319+
## Best Practices
320+
321+
1. **Always Include Full Chain**: When creating presentations with delegated credentials, include the complete delegation chain from root to leaf.
322+
323+
2. **Use Specific mayClaim Values**: Be explicit about which claims a delegate can issue. Avoid overly broad delegations.
324+
325+
3. **Implement Cedar Policies**: Use Cedar policies to enforce business rules like maximum delegation depth and claim requirements.
326+
327+
4. **Handle Verification Failures**: Check both the overall `verified` status and the `delegationResult.decision` to understand why verification failed.
328+
329+
330+
## Testing
331+
332+
See `integration-tests/delegatable-credentials.test.ts` for comprehensive test examples including:
333+
334+
- Issuing valid delegation credentials
335+
- Issuing delegated credentials with proper chain references
336+
- Creating and verifying presentations with delegation chains
337+
- Enforcing authorization with Cedar policies
338+
- Handling unauthorized delegations
339+
- Multi-level delegation chains
340+
- Integration with Presentation Exchange
341+
342+
Run the tests with:
343+
```bash
344+
npm test integration-tests/delegatable-credentials.test.ts
345+
```
346+
347+
## References
348+
349+
- [W3C Verifiable Credentials](https://www.w3.org/TR/vc-data-model/)
350+
- [Cedar Policy Language](https://www.cedarpolicy.com/)
351+
- [Presentation Exchange](https://identity.foundation/presentation-exchange/)

0 commit comments

Comments
 (0)