Issue a Verifiable Credential

Issue a JSON-LD Verifiable Credential, signed by a did:cheqd Decentralized Identifier (DID), using Credo.

Using the Issue Credential v2 Protocol, you can issue JSON-LD Verifiable Credentials signed by a did:cheqd identifier with just a few lines of code. This guide walks through the full flow using the Credo Agent.

Prerequisites

Before you begin, ensure you have:

Step 1: Install dependencies

npm install @credo-ts/core @credo-ts/node @credo-ts/askar @credo-ts/cheqd
npm install @hyperledger/aries-askar-nodejs

Step 2: Set up the Issuer Agent

The issuer agent requires the cheqd module for DID operations and additional modules for W3C JSON-LD credential processing.

Issuer
import type { InitConfig } from '@credo-ts/core'
import { AskarModule } from '@credo-ts/askar'
import {
  Agent,
  CredentialsModule,
  V2CredentialProtocol,
  JsonLdCredentialFormatService,
  DidsModule,
  HttpOutboundTransport,
  WsOutboundTransport,
  ProofsModule,
  V2ProofProtocol,
  DifPresentationExchangeProofFormatService,
  CacheModule,
  InMemoryLruCache,
  W3cCredentialsModule,
  KeyType,
  DidDocumentBuilder,
  utils,
  getEd25519VerificationKey2018,
} from '@credo-ts/core'
import { agentDependencies, HttpInboundTransport } from '@credo-ts/node'
import { ariesAskar } from '@hyperledger/aries-askar-nodejs'
import { CheqdModule, CheqdModuleConfig, CheqdDidRegistrar, CheqdDidResolver } from '@credo-ts/cheqd'

let issuerDid: string

const issuerConfig: InitConfig = {
  label: 'cheqd-jsonld-issuer',
  walletConfig: {
    id: 'cheqd-issuer-wallet',
    key: 'testkey0000000000000000000000000',
  },
}

const initializeIssuerAgent = async () => {
  const issuer = new Agent({
    config: issuerConfig,
    dependencies: agentDependencies,
    modules: {
      askar: new AskarModule({ ariesAskar }),
      dids: new DidsModule({
        registrars: [new CheqdDidRegistrar()],
        resolvers: [new CheqdDidResolver()],
      }),
      cheqd: new CheqdModule(
        new CheqdModuleConfig({
          networks: [
            {
              network: 'testnet', // or 'mainnet'
              cosmosPayerSeed: 'your-cosmos-payer-seed-here',
            },
          ],
        })
      ),
      credentials: new CredentialsModule({
        credentialProtocols: [
          new V2CredentialProtocol({
            credentialFormats: [new JsonLdCredentialFormatService()],
          }),
        ],
      }),
      proofs: new ProofsModule({
        proofProtocols: [
          new V2ProofProtocol({
            proofFormats: [new DifPresentationExchangeProofFormatService()],
          }),
        ],
      }),
      cache: new CacheModule({
        cache: new InMemoryLruCache({ limit: 100 }),
      }),
      w3cCredentials: new W3cCredentialsModule({}),
    },
  })

  // Register transports
  issuer.registerOutboundTransport(new WsOutboundTransport())
  issuer.registerOutboundTransport(new HttpOutboundTransport())
  issuer.registerInboundTransport(new HttpInboundTransport({ port: 3001 }))

  await issuer.initialize()
  return issuer
}

Step 3: Set up the Holder Agent

The holder agent needs to resolve cheqd DIDs and handle JSON-LD credentials.

Step 4: Create Issuer DID

Step 5: Create connection between Issuer and Holder

Use any supported method to create a connection with the Holder of the credential. Automated out-of-band protocol is recommended.

5a: Issuer creates Connection Invite

The Issuer agent will create a new connection invite for the Holder. This is needed to securely communicate between the Issuer and the Holder agents.

5b: Holder receives invitation

The above request will have an invitation in the response. Holder will have to copy that invitation and pass URL as invitationUrl in the following code:

Step 6: Set up Credential Event Listeners

Both agents need event listeners to handle the credential exchange protocol automatically.

Step 7: Holder proposes the Credential

In this example, we will initiate the credential issuance process by having the holder propose a credential.

The Credential Acceptance and storage is handled automatically by the event listeners registered for both Issuer and Holder.

Last updated

Was this helpful?