Skip to content

Instantly share code, notes, and snippets.

@blackgirlbytes
Created December 7, 2023 16:48
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save blackgirlbytes/48d2d09f4785f6399f850a5c58709c28 to your computer and use it in GitHub Desktop.
Save blackgirlbytes/48d2d09f4785f6399f850a5c58709c28 to your computer and use it in GitHub Desktop.
Creating a verifiable credential

How to create a verifiable credential

Use node 20.9

Install dependencies

    "@web5/api": "^0.8.2",
    "@web5/credentials": "^0.3.2",
    "@web5/crypto": "^0.2.3",
    "@web5/dids": "^0.2.2"

Import dependencies

import { VerifiableCredential, PresentationExchange } from "@web5/credentials";
import { DidKeyMethod } from '@web5/dids';
import { Ed25519 } from '@web5/crypto';
import { Web5 } from '@web5/api';

Create DIDs for the issuer (you) and for the subject (your friends)

// Prerequisites: Create issuer (ticket issuer)
const issuerDid = await DidKeyMethod.create();

// Prerequisites: Create subject (alice)
const friendDid = await DidKeyMethod.create();

Create a class for a Trusted Friend Verifiable Credential

class TrustedFriendCredential {
    constructor(issuerDid, friendDid, trustLevel) {
        this.issuerDid = issuerDid;
        this.subjectDid = friendDid;
        this.trustLevel = trustLevel; // e.g., 'trusted'
    }
}

Create a new instance of the trusted verifiable credential class

const trustedFriendData = new TrustedFriendCredential(issuerDid, friendDid, "trusted");

Create a verifiable Credential using VerifiableCredential.create()

// needs: type, issuer, subject, data
const vc = await VerifiableCredential.create({
    type: 'TrustedFriendCredential',
    issuer: issuerDid.did,
    subject: friendDid.did,
    data: trustedFriendData
})

Sign the credential

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")

Verify the credential

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")
}

Parse the credential

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 - Presentation Definition

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' }
                    }
                ]
            }
        }
    ]
};

Presentation Exchange - Satisfies Presentation Exchange

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)
}

Store the VC in your DWN

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")

Read the VC from your DWN

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")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment