Skip to main content

Overview

The Verifiable Credentials SDK provides tools for working with blockchain-based verifiable credentials (VCs), including:
  • Retrieving credentials from NFTs
  • Verifying credential signatures and validity
  • Decrypting encrypted credentials
  • Managing credential collections

Installation

npm install @crossmint/client-sdk-verifiable-credentials

Setup

Configure the SDK with your Crossmint API key:
import { crossmintAPI } from '@crossmint/client-sdk-verifiable-credentials';

crossmintAPI.init({
  apiKey: 'your-api-key'
});

CredentialService

Service for retrieving verifiable credentials from different sources.

Creating an Instance

import { CredentialService } from '@crossmint/client-sdk-verifiable-credentials';

const credentialService = new CredentialService();
The service includes default retrieval procedures for:
  • IPFS: Credentials stored on IPFS
  • Crossmint: Credentials stored in Crossmint’s API

getById

Retrieve a credential by its ID from Crossmint.
const credential = await credentialService.getById(
  'cred_123456789'
);

if (credential) {
  console.log('Credential:', credential);
  console.log('Subject:', credential.credentialSubject);
}
credentialId
string
required
The unique identifier of the credential
Returns: Promise<VerifiableCredentialType | null> Throws: Error if retrieval fails

getCredential

Retrieve a credential from an NFT’s metadata.
const collection: CredentialsCollection = {
  contract: {
    address: '0x123...abc',
    chain: 'ethereum'
  },
  credentials: [
    {
      tokenId: '1',
      credentialSubject: { id: 'did:example:123' }
    }
  ]
};

const credential = await credentialService.getCredential(
  collection,
  '1' // tokenId
);
collection
CredentialsCollection
required
Credential collection containing contract and credential metadata
tokenId
string
required
Token ID of the NFT containing the credential
Returns: Promise<VerifiableCredentialType>

getCredentialNfts

Retrieve all NFTs that are verifiable credentials for a given wallet.
import { 
  getCredentialNfts,
  type VCChain,
  type CredentialFilter 
} from '@crossmint/client-sdk-verifiable-credentials';

const collections = await getCredentialNfts(
  'ethereum' as VCChain,
  '0x1234...5678',
  {
    credentialType: 'VerifiableCredential',
    issuer: 'did:web:issuer.example.com'
  }
);

collections.forEach(collection => {
  console.log('Contract:', collection.contract.address);
  console.log('Credentials:', collection.credentials.length);
});
chain
VCChain
required
Blockchain to query
wallet
string
required
Wallet address to query
filters
CredentialFilter
default:"{}"
Optional filters to select specific credentials
Returns: Promise<CredentialsCollection[]> Requires: API key with credentials.read scope

verifyCredential

Verify the cryptographic signature and validity of a credential.
import { verifyCredential } from '@crossmint/client-sdk-verifiable-credentials';

const isValid = await verifyCredential(credential);

if (isValid) {
  console.log('Credential is valid and signed correctly');
} else {
  console.error('Credential verification failed');
}
credential
VerifiableCredential
required
The credential to verify
Returns: Promise<boolean> - true if the credential is valid and signature is correct

Lit

Class for decrypting verifiable credentials encrypted with Lit Protocol.

Creating an Instance

import { Lit, type LitNetwork } from '@crossmint/client-sdk-verifiable-credentials';

const lit = new Lit(
  'cayenne' as LitNetwork, // or 'habanero', 'manzano'
  undefined, // optional custom auth sig
  false // debug mode
);
network
LitNetwork
required
Lit Protocol network
capacityDelegationAuthSig
AuthSig
Custom capacity delegation signature. If not provided, uses Crossmint’s signature (requires credentials.decrypt scope).
debug
boolean
default:false
Enable debug logging

decrypt

Decrypt an encrypted verifiable credential.
import { 
  Lit,
  type EncryptedVerifiableCredential 
} from '@crossmint/client-sdk-verifiable-credentials';

const encryptedCredential: EncryptedVerifiableCredential = {
  id: 'cred_encrypted_123',
  payload: 'encrypted_data_here'
};

const lit = new Lit('cayenne');
const decryptedCredential = await lit.decrypt(encryptedCredential);

console.log('Decrypted credential:', decryptedCredential.credentialSubject);
credential
EncryptedVerifiableCredential
required
The encrypted credential to decrypt
Returns: Promise<VerifiableCredential> - The decrypted credential Note: User will be prompted to sign a message to decrypt the credential

CrossmintDecrypt

Decrypt credentials using Crossmint’s decryption service.
import { CrossmintDecrypt } from '@crossmint/client-sdk-verifiable-credentials';

const decryptedCredential = await CrossmintDecrypt({
  encryptedCredential,
  secret: 'decryption_secret_from_api'
});
options
object
required
Returns: Promise<VerifiableCredential>

Types

VerifiableCredential

interface VerifiableCredential {
  id: string;
  credentialSubject: any;
  validUntil?: string;
  name?: string;
  description?: string;
  nft: Nft;
  issuer: { id: string };
  type: string[];
  validFrom: string;
  '@context': string[];
  proof?: {
    proofValue: string;
    [key: string]: any;
  };
}

EncryptedVerifiableCredential

interface EncryptedVerifiableCredential {
  id: string;
  payload: string; // Encrypted data
}

VerifiableCredentialType

type VerifiableCredentialType = 
  | VerifiableCredential 
  | EncryptedVerifiableCredential;

CredentialsCollection

interface CredentialsCollection {
  contract: {
    address: string;
    chain: string;
  };
  credentials: Array<{
    tokenId: string;
    credentialSubject: any;
    // ... other credential fields
  }>;
}

CredentialFilter

interface CredentialFilter {
  credentialType?: string;
  issuer?: string;
  validFrom?: string;
  validUntil?: string;
}

Utility Functions

isVerifiableCredential

Type guard to check if an object is a VerifiableCredential.
import { isVerifiableCredential } from '@crossmint/client-sdk-verifiable-credentials';

if (isVerifiableCredential(credential)) {
  console.log('Type:', credential.type);
  console.log('Subject:', credential.credentialSubject);
}

isEncryptedVerifiableCredential

Type guard to check if an object is an EncryptedVerifiableCredential.
import { isEncryptedVerifiableCredential } from '@crossmint/client-sdk-verifiable-credentials';

if (isEncryptedVerifiableCredential(credential)) {
  console.log('Credential is encrypted, needs decryption');
  const decrypted = await lit.decrypt(credential);
}

isCredentialType

Check if a credential matches a specific type.
import { isCredentialType } from '@crossmint/client-sdk-verifiable-credentials';

if (isCredentialType(credential, 'VerifiableCredential')) {
  console.log('This is a standard verifiable credential');
}

Complete Example

import {
  crossmintAPI,
  CredentialService,
  getCredentialNfts,
  verifyCredential,
  Lit,
  isEncryptedVerifiableCredential
} from '@crossmint/client-sdk-verifiable-credentials';

// Initialize
crossmintAPI.init({ apiKey: 'your-api-key' });

// Get all credential NFTs for a wallet
const collections = await getCredentialNfts(
  'ethereum',
  '0x1234...5678',
  { credentialType: 'EducationCredential' }
);

console.log(`Found ${collections.length} collections`);

// Get a specific credential
const credentialService = new CredentialService();
const credential = await credentialService.getById('cred_123');

if (!credential) {
  console.error('Credential not found');
  return;
}

// Check if encrypted
if (isEncryptedVerifiableCredential(credential)) {
  console.log('Credential is encrypted, decrypting...');
  
  const lit = new Lit('cayenne');
  const decrypted = await lit.decrypt(credential);
  
  // Verify the decrypted credential
  const isValid = await verifyCredential(decrypted);
  
  if (isValid) {
    console.log('Valid credential!');
    console.log('Subject:', decrypted.credentialSubject);
    console.log('Issuer:', decrypted.issuer.id);
    console.log('Valid from:', decrypted.validFrom);
    console.log('Valid until:', decrypted.validUntil);
  } else {
    console.error('Credential verification failed');
  }
} else {
  // Verify unencrypted credential
  const isValid = await verifyCredential(credential);
  console.log('Credential is valid:', isValid);
}

Best Practices

  1. API Key Scope: Ensure your API key has the required scopes:
    • credentials.read for retrieving credentials
    • credentials.decrypt for using Crossmint’s Lit delegation signature
  2. Verification: Always verify credentials before trusting their contents:
    const isValid = await verifyCredential(credential);
    if (!isValid) throw new Error('Invalid credential');
    
  3. Error Handling: Handle encryption/decryption errors gracefully:
    try {
      const decrypted = await lit.decrypt(encryptedCredential);
    } catch (error) {
      console.error('Decryption failed:', error.message);
    }
    
  4. Filtering: Use filters to reduce API calls and improve performance:
    const collections = await getCredentialNfts(
      'ethereum',
      walletAddress,
      {
        issuer: 'did:web:trusted-issuer.com',
        credentialType: 'EducationCredential'
      }
    );
    
  5. Type Checking: Use type guards to handle both encrypted and unencrypted credentials:
    if (isEncryptedVerifiableCredential(credential)) {
      // Handle encrypted credential
    } else {
      // Handle unencrypted credential
    }
    

Build docs developers (and LLMs) love