Installation
npm install @crossmint/client-sdk-verifiable-credentials
Overview
The Verifiable Credentials SDK enables applications to work with verifiable credentials (VCs) stored as NFTs on multiple blockchains. It supports:
Fetching credentials from user wallets
Verifying credential authenticity and validity
Decrypting encrypted credentials
Presenting credentials to verifiers
Quick Start
import {
getCredentialNfts ,
verifyCredential ,
type VerifiableCredential
} from '@crossmint/client-sdk-verifiable-credentials' ;
// Fetch all credentials for a wallet
const collections = await getCredentialNfts (
'polygon' ,
'0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb'
);
// Get first credential
const credential = collections [ 0 ]. credentials [ 0 ];
// Verify the credential
const isValid = await verifyCredential ( credential );
console . log ( 'Credential valid:' , isValid );
Core Concepts
Verifiable Credential Structure
Credentials follow the W3C Verifiable Credentials standard:
interface VerifiableCredential {
id : string ;
credentialSubject : any ; // Claims about the subject
issuer : { id : string }; // Issuer DID
type : string []; // Credential types
validFrom : string ; // ISO 8601 date
validUntil ?: string ; // Optional expiration
name ?: string ;
description ?: string ;
nft : Nft ; // Associated NFT metadata
'@context' : string [];
proof ?: { // Cryptographic proof
proofValue : string ;
[ key : string ] : any ;
};
}
See type definition at /home/daytona/workspace/source/packages/client/verifiable-credentials/src/verifiableCredentialsSDK/types/verifiableCredential.ts
Encrypted Credentials
Some credentials are encrypted on-chain:
interface EncryptedVerifiableCredential {
id : string ;
payload : string ; // Encrypted credential data
}
type VerifiableCredentialType =
| VerifiableCredential
| EncryptedVerifiableCredential ;
Fetching Credentials
Get Credential NFTs
Fetch all verifiable credentials for a wallet:
import { getCredentialNfts , type VCChain } from '@crossmint/client-sdk-verifiable-credentials' ;
const collections = await getCredentialNfts (
'polygon' as VCChain ,
'0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb' ,
{
// Optional filters
credentialTypes: [ 'VerifiableCredential' , 'EmploymentCredential' ],
issuerAddress: '0x123...' , // Filter by issuer
}
);
collections . forEach ( collection => {
console . log ( 'Collection:' , collection . name );
console . log ( 'Credentials:' , collection . credentials . length );
collection . credentials . forEach ( cred => {
console . log ( ' -' , cred . name , '(Type:' , cred . type , ')' );
});
});
Parameters
Blockchain to query. Supported chains:
'polygon'
'ethereum'
'arbitrum'
'optimism'
'base'
'zora'
Wallet address to fetch credentials for
Optional filters: {
credentialTypes ?: string []; // Filter by credential type
issuerAddress ?: string ; // Filter by issuer address
}
Return Type
interface CredentialsCollection {
name : string ; // Collection name
credentials : VerifiableCredentialType [];
contractAddress : string ;
chain : VCChain ;
}
See implementation at /home/daytona/workspace/source/packages/client/verifiable-credentials/src/presentation/getCredentialNfts.ts
Get Single Credential
Fetch a specific credential by NFT locator:
import {
getCredentialNFTFromLocator ,
CredentialService
} from '@crossmint/client-sdk-verifiable-credentials' ;
// Fetch credential NFT metadata
const nft = await getCredentialNFTFromLocator (
'polygon:0x123.../tokenId/456' ,
{ /* chain RPC config */ }
);
// Fetch full credential data
const credentialService = new CredentialService ();
const credential = await credentialService . getCredential (
nft ,
'polygon'
);
Verifying Credentials
Verify Credential
Verify a credential’s authenticity and validity:
import { verifyCredential } from '@crossmint/client-sdk-verifiable-credentials' ;
const isValid = await verifyCredential ( credential );
if ( isValid ) {
console . log ( 'Credential is valid and verified' );
} else {
console . log ( 'Credential verification failed' );
}
Verification checks:
Cryptographic proof signature
Expiration date (if present)
Issuer signature
Credential format compliance
Encrypted credentials must be decrypted before verification.
Decrypting Credentials
Using Lit Protocol
Decrypt credentials encrypted with Lit Protocol:
import { Lit } from '@crossmint/client-sdk-verifiable-credentials' ;
import type { EncryptedVerifiableCredential } from '@crossmint/client-sdk-verifiable-credentials' ;
// Initialize Lit client
const lit = new Lit ();
await lit . connect ();
// Decrypt credential
const decrypted = await lit . decryptVerifiableCredential (
encryptedCredential as EncryptedVerifiableCredential ,
authSig , // Wallet signature for authentication
chain
);
console . log ( 'Decrypted credential:' , decrypted );
Using Wallet Decryption
Decrypt using a wallet’s native encryption:
import {
CrossmintDecrypt ,
CrossmintMetamaskDecrypt
} from '@crossmint/client-sdk-verifiable-credentials' ;
// Generic wallet decryption
const decryptor = new CrossmintDecrypt ( walletProvider );
const decrypted = await decryptor . decrypt ( encryptedCredential );
// MetaMask-specific decryption
const metamaskDecryptor = new CrossmintMetamaskDecrypt ( ethereum );
const decrypted = await metamaskDecryptor . decrypt ( encryptedCredential );
Credential Presentation
Fetch metadata about credential contracts:
import { ContractMetadataService } from '@crossmint/client-sdk-verifiable-credentials' ;
const metadataService = new ContractMetadataService ();
const metadata = await metadataService . getContractMetadata (
'polygon' ,
'0x123...' // Contract address
);
console . log ( 'Contract name:' , metadata . name );
console . log ( 'Contract description:' , metadata . description );
console . log ( 'Contract image:' , metadata . image );
Type Utilities
Type Guards
Check credential types:
import {
isVerifiableCredential ,
isEncryptedVerifiableCredential ,
isCredentialType ,
isVcChain ,
} from '@crossmint/client-sdk-verifiable-credentials' ;
if ( isVerifiableCredential ( credential )) {
// TypeScript knows this is VerifiableCredential
console . log ( 'Issuer:' , credential . issuer . id );
}
if ( isEncryptedVerifiableCredential ( credential )) {
// TypeScript knows this is EncryptedVerifiableCredential
console . log ( 'Encrypted payload:' , credential . payload );
}
if ( isCredentialType ( credential , 'EmploymentCredential' )) {
console . log ( 'This is an employment credential' );
}
if ( isVcChain ( 'polygon' )) {
// TypeScript knows this is a valid VCChain
}
Advanced Features
Custom Retrieval Procedures
Implement custom credential retrieval:
import {
ipfsRetrievalProcedure ,
crossmintRetrievalProcedure
} from '@crossmint/client-sdk-verifiable-credentials' ;
// Retrieve from IPFS
const credential = await ipfsRetrievalProcedure (
'ipfs://QmXxx...' ,
'polygon'
);
// Retrieve from Crossmint API
const credential2 = await crossmintRetrievalProcedure (
nft ,
'ethereum'
);
Wallet Authentication Service
Authenticate wallet signatures for credential operations:
import { WalletAuthService } from '@crossmint/client-sdk-verifiable-credentials' ;
const authService = new WalletAuthService ();
const authSig = await authService . getAuthSignature (
wallet ,
'polygon'
);
// Use authSig for Lit Protocol or other operations
Crossmint API Client
Direct API access for advanced use cases:
import { crossmintAPI } from '@crossmint/client-sdk-verifiable-credentials' ;
const client = crossmintAPI ({
apiKey: 'YOUR_API_KEY' ,
baseUrl: 'https://www.crossmint.com/api' ,
});
// Make custom API calls
const response = await client . get ( '/credentials/...' );
Type Exports
All exported types:
import type {
// Core credential types
VerifiableCredential ,
EncryptedVerifiableCredential ,
VerifiableCredentialType ,
// NFT types
VCNFT ,
// Chain types
VCChain ,
ChainRPCConfig ,
// Collection types
Collection ,
CredentialsCollection ,
CredentialMetadata ,
// Filter types
CredentialFilter ,
// Encryption types
VerifiableCredentialEncryption ,
VerifiableCredentialEncryptionType ,
} from '@crossmint/client-sdk-verifiable-credentials' ;
Complete Example
import {
getCredentialNfts ,
verifyCredential ,
isVerifiableCredential ,
isEncryptedVerifiableCredential ,
Lit ,
type VCChain ,
type VerifiableCredential ,
} from '@crossmint/client-sdk-verifiable-credentials' ;
async function fetchAndVerifyCredentials (
chain : VCChain ,
walletAddress : string
) {
// 1. Fetch all credentials
const collections = await getCredentialNfts ( chain , walletAddress , {
credentialTypes: [ 'VerifiableCredential' , 'EmploymentCredential' ],
});
console . log ( `Found ${ collections . length } collections` );
// 2. Process each credential
for ( const collection of collections ) {
console . log ( ` \n Collection: ${ collection . name } ` );
for ( const credential of collection . credentials ) {
// 3. Handle encrypted credentials
if ( isEncryptedVerifiableCredential ( credential )) {
console . log ( ' - Encrypted credential found' );
// Decrypt with Lit Protocol
const lit = new Lit ();
await lit . connect ();
const decrypted = await lit . decryptVerifiableCredential (
credential ,
authSig ,
chain
);
credential = decrypted ;
}
// 4. Verify credential
if ( isVerifiableCredential ( credential )) {
const isValid = await verifyCredential ( credential );
console . log ( ` - ${ credential . name } :` , isValid ? '✓ Valid' : '✗ Invalid' );
console . log ( ` Type: ${ credential . type . join ( ', ' ) } ` );
console . log ( ` Issuer: ${ credential . issuer . id } ` );
console . log ( ` Valid from: ${ credential . validFrom } ` );
if ( credential . validUntil ) {
const expired = new Date ( credential . validUntil ) < new Date ();
console . log ( ` Valid until: ${ credential . validUntil } ${ expired ? '(EXPIRED)' : '' } ` );
}
}
}
}
}
// Usage
await fetchAndVerifyCredentials (
'polygon' ,
'0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb'
);
Best Practices
Always Verify Credentials
Never trust credential data without verification: const isValid = await verifyCredential ( credential );
if ( ! isValid ) {
throw new Error ( 'Invalid credential' );
}
// Now safe to use credential.credentialSubject
Verify credentials haven’t expired: if ( credential . validUntil ) {
const expired = new Date ( credential . validUntil ) < new Date ();
if ( expired ) {
console . warn ( 'Credential has expired' );
}
}
Handle Encrypted Credentials
Always check if a credential is encrypted before accessing data: if ( isEncryptedVerifiableCredential ( credential )) {
credential = await decrypt ( credential );
}
if ( isVerifiableCredential ( credential )) {
// Now safe to access credentialSubject
console . log ( credential . credentialSubject );
}
Use filters to reduce data transfer and processing: const collections = await getCredentialNfts (
'polygon' ,
walletAddress ,
{
credentialTypes: [ 'EmploymentCredential' ],
issuerAddress: trustedIssuerAddress ,
}
);
Error Handling
import {
getCredentialNfts ,
verifyCredential
} from '@crossmint/client-sdk-verifiable-credentials' ;
try {
const collections = await getCredentialNfts ( 'polygon' , walletAddress );
for ( const collection of collections ) {
for ( const credential of collection . credentials ) {
try {
const isValid = await verifyCredential ( credential );
if ( ! isValid ) {
console . warn ( 'Credential verification failed:' , credential . id );
}
} catch ( error ) {
console . error ( 'Verification error:' , error );
// Continue processing other credentials
}
}
}
} catch ( error ) {
console . error ( 'Failed to fetch credentials:' , error );
// Handle network or API errors
}
Supported Chains
The SDK supports verifiable credentials on:
Polygon (polygon)
Ethereum (ethereum)
Arbitrum (arbitrum)
Optimism (optimism)
Base (base)
Zora (zora)
Next Steps
Issue Credentials Learn how to issue credentials
React Integration Use with React components
API Reference Explore the complete API
W3C VC Standard Learn about VC standards