Private Delegation
This tutorial follows the lifecycle of a delegated credential. It builds builds on previous turorials Issuance, Presentation, Verification and Claim Deduction.
Create a Delegation
Let's assume some root authority, did:ex:a
, wants grant did:ex:b
full authority to make claims on behalf of did:ex:a
. To do this did:ex:a
will issue a delegation credential to did:ex:b
.
Boilerplate
const { v4: uuidv4 } = require('uuid');
function uuid() {
return `uuid:${uuidv4()}`;
}
// Check out the Issuance, Presentation, Verification tutorial for info on signing
// credentials.
function signCredential(cred, issuer_secret) { ... }
// Check out the Issuance, Presentation, Verification tutorial for info on verifying
// VCDM presentations.
async function verifyPresentation(presentation) { ... }
const delegation = {
"@context": ["https://www.w3.org/2018/credentials/v1"],
id: uuid(),
type: ["VerifiableCredential"],
issuer: "did:ex:a",
credentialSubject: {
id: "did:ex:b",
"https://rdf.dock.io/alpha/2021#mayClaim":
"https://rdf.dock.io/alpha/2021#ANYCLAIM",
},
issuanceDate: new Date().toISOString(),
};
const signed_delegation = signCredential(delegation, dida_secret);
Next did:ex:a
sends the signed credential to did:ex:b
.
Issue a Credential as a Delegate
did:ex:b
accepts the delegation credential from did:ex:a
. Now did:ex:b
can use the delegation to make arbitrary attestations on behalf of did:ex:a
.
const newcred = {
"@context": ["https://www.w3.org/2018/credentials/v1"],
id: uuid(),
type: ["VerifiableCredential"],
issuer: "did:ex:b",
credentialSubject: {
id: "did:ex:c",
"https://example.com/score": 100,
},
issuanceDate: new Date().toISOString(),
};
const signed_newcred = signCredential(newcred, didb_secret);
So far we have two credentials, signed_delegation
and signed_newcred
. signed_delegation
proves that any claim made by did:ex:b
is effectively a claim made by did:ex:a
. signed_newcred
proves tha did:ex:b
claims that did:ex:c
has a score of 100. By applying one of the logical rules provided by the sdk, we can infer that did:ex:a
claims did:ex:c
has a score of 100. The logical rule named MAYCLAIM_DEF_1
will work for this use-case. MAYCLAIM_DEF_1
will be used by the verifier.
Now did:ex:b
has both signed credentials. did:ex:b
may now pass both credentials to the holder. In this case the holder is did:ex:c
. did:ex:c
also happens to be the subject of one of the credentials.
Present a Delegated Credential
did:ex:c
now holds two credentials, signed_delegation
and signed_newcred
. Together they prove that did:ex:a
indirectly claims did:ex:c
to have a score of 100. did:ex:c
wants to prove this statement to another party, a verifier. did:ex:c
must bundle the two credentials into a VCDM presentation.
let presentation = {
"@context": ["https://www.w3.org/2018/credentials/v1"],
type: ["VerifiablePresentation"],
id: uuid(),
holder: `did:ex:c`,
verifiableCredential: [signed_delegation, signed_newcred],
};
presentation
is sent to the verifier.
Accept a Delegated Credential
The verifier receives presentation
, verifies the enclosed credentials, then reasons over the union of all the credentials in the bundle using the rule MAYCLAIM_DEF_1
. The process is the one outlined in Verifier-Side Reasoning but using a different composite claim and a different rule list.
import { MAYCLAIM_DEF_1 } from '@docknetwork/credential-sdk/rdf-and-cd';
import { proveCompositeClaims } from '../src/utils/cd';
import jsonld from 'jsonld';
const compositeClaim = [
{ Iri: 'did:ex:c' },
{ Iri: 'https://example.com/score' },
{ Literal: { datatype: 'http://www.w3.org/2001/XMLSchema#integer', value: '100' } }
{ Iri: 'did:ex:a' },
];
let ver = await verifyPresentation(presentation);
if (!ver.verified) {
throw ver;
}
const expPres = await jsonld.expand(presentation);
try {
await proveCompositeClaims(expPres, [compositeClaim], MAYCLAIM_DEF_1);
console.log('the composite claim was shown to be true');
} except (e) {
console.error('veracity of the composite claim is unknown');
}