"@web5/api": "^0.8.2",
"@web5/credentials": "^0.3.2",
"@web5/crypto": "^0.2.3",
"@web5/dids": "^0.2.2"
import { VerifiableCredential, PresentationExchange } from "@web5/credentials";
import { DidKeyMethod } from '@web5/dids';
import { Ed25519 } from '@web5/crypto';
import { Web5 } from '@web5/api';
// Prerequisites: Create issuer (ticket issuer)
const issuerDid = await DidKeyMethod.create();
// Prerequisites: Create subject (alice)
const friendDid = await DidKeyMethod.create();
class TrustedFriendCredential {
constructor(issuerDid, friendDid, trustLevel) {
this.issuerDid = issuerDid;
this.subjectDid = friendDid;
this.trustLevel = trustLevel; // e.g., 'trusted'
}
}
const trustedFriendData = new TrustedFriendCredential(issuerDid, friendDid, "trusted");
// needs: type, issuer, subject, data
const vc = await VerifiableCredential.create({
type: 'TrustedFriendCredential',
issuer: issuerDid.did,
subject: friendDid.did,
data: trustedFriendData
})
Signing the credential with the issuer's private key ensures its integrity and authenticity. It provides a cryptographic proof that the credential has not been tampered with and is indeed issued by the claimed issuer.
- privateKey: Extracts the private key from the issuer's DID.
- signOptions: Configuration for signing the VC.
- signedVcJwt: The JWT (JSON Web Token) format of the signed VC.
const privateKey = issuerDid.keySet.verificationMethodKeys[0].privateKeyJwk;
const signOptions = {
issuerDid: issuerDid.did,
subjectDid: friendDid.did,
kid: `${issuerDid.did}#${issuerDid.did.split(':')[2]}`,
signer: async (data) => await Ed25519.sign({ data, key: privateKey })
};
const signedVcJwt = await vc.sign(signOptions);
console.log("\nSigned VC: \n" + signedVcJwt + "\n")
You're verifying the signed VC to ensure its integrity and authenticity.
try {
await VerifiableCredential.verify(signedVcJwt)
console.log("\nVC Verification successful!\n")
} catch (err) {
console.log("\nVC Verification failed: " + err.message + "\n")
}
allows you to inspect the contents of the signed JWT, ensuring that the data within the credential is as expected. It's a form of validation and inspection.
const parsedVc = VerifiableCredential.parseJwt(signedVcJwt)
console.log("\nParsed VC: \n" + parsedVc.toString() + "\n")
Presentation exchange allows a VC holder to present their credentials in a secure and verifiable manner. if a service requires age verification, the holder can present a VP containing only the age-related information from their ID credential, rather than sharing the entire ID.
const presentationDefinition = {
id: 'trustedFriendPresDef',
name: 'Trusted Friend Presentation Definition',
purpose: 'To verify if the user is a trusted friend',
input_descriptors: [
{
id: 'trustedFriendDescriptor',
purpose: 'We need to verify you are a trusted friend',
constraints: {
fields: [
{
path: ['$.credentialSubject.trustLevel'],
filter: { type: 'string', pattern: 'trusted' }
}
]
}
}
]
};
signed VC meets the criteria set in the presentation definition. This step is crucial for automated verification processes in various applications.
// Satisfies Presentation Definition
try {
const validated = await PresentationExchange.validateDefinition(presentationDefinition);
console.log(validated)
PresentationExchange.satisfiesPresentationDefinition([signedVcJwt], presentationDefinition);
console.log("\nVC Satisfies Presentation Definition!\n")
} catch (err) {
console.log("VC does not satisfy Presentation Definition: " + err.message)
}
const { web5, did} = await Web5.connect();
// Storing VC in DWN
const { record } = await web5.dwn.records.create({
data: signedVcJwt,
message: {
schema: 'VerifiableCredential',
dataFormat: 'application/vc+jwt',
},
});
console.log("\nVC Record ID: " + record.id + "\n")
let { record: readRecord } = await web5.dwn.records.read({
message: {
filter: {
recordId: record.id
}
}
});
const readVcJwt = await readRecord.data.text();
console.log("\nVC Record: \n" + readVcJwt + "\n")