Ezrah Creds SDK
This document provides a comprehensive overview of how to use the Ezrah Creds SDK, a TypeScript package that simplifies the creation, issuance, and verification of Verifiable Credentials (VCs). It also includes tools for managing Decentralized Identifiers (DIDs), webhook integrations, organization settings, and analytics — all designed to integrate seamlessly with Ezrah’s identity infrastructure.
[!Note] Current SDK Version: @coincord/ezrah-creds-sdk@1.0.0-alpha.12
Installation
To start using the Ezrah Creds SDK, install it via npm or yarn. This will add the SDK to your project so you can begin issuing and verifying credentials and interacting with the Ezrah platform programmatically.
Ezrah(Coincord) Libraries are hosted on github not npm so add this to your .npmrc file, (vim ~/.npmrc)
@coincord:registry=https://npm.pkg.github.com
With this set your environment will know to check github for coincord libraries instead of npm
# npm
npm install @coincord/ezrah-creds-sdk
or
# yarn
yarn install @coincord/ezrah-creds-sdk
Also setup your environment configs with the following configurations.
EZRAH_CREDENTIAL_BASE_URL=api.ezrah.co
EZRAH_ORGANIZATION_API_KEY=<your_api_key>
You can generate new API keys on your Ezrah Dashboard
Getting Started
This section initializes the SDK. Import the main class and instantiate it to begin accessing all available methods. This object becomes your main entry point for issuing credentials, managing webhooks, and more.
import EzrahCredential from '@coincord/ezrah-creds-sdk';
const ezrah = new EzrahCredential();
Credential Management
This section contains methods to issue Verifiable Credentials (VCs) to users. These credentials can contain any structured data and are tied to a DID. Use this to programmatically issue credentials for KYC, employment, certification, and more. These credentials can contain any structured data and are tied to a DID. Use this to programmatically issue credentials for KYC, employment, certification, and more.
Issue a pre-defined Credential
Use this method when you already have a pre-defined credential template (claim ID) and want to issue a VC to a user identified by their DID.
const credential = await ezrah.issueCredential({
claimID: 'template123',
did: 'did:ezrah:abc123',
claims: {
name: 'John Doe',
role: 'Admin',
},
});
Response
{
proof: string,
proof_type: string,
credential: string
}
Issue a Credential via SDK:
A simplified method to issue credentials using just the basic details (title, claim ID, and fields). Ideal for quick issuance flows or UI-based forms.
The claims must match the claims referenced within the template id. it doesn’t need to be a complete match of the list but a partial match.
const credential = await ezrah.issueCredentialSDK({
title: "Request title",
template_claim_id: "a_claims_template_from_template_list",
claims: {
name: "John Doe",
role: "Admin"
},
options: {
policy_control: false // default
}
})
Update Credential Policy
This method allows you to update the policy control state of a credential.
const result = await ezrah.policyControlCredential({
credential_urn: "urn:vc:abc123...",
action: "REVOKE", // or "REVOKE, EXPIRY, SUSPEND"
state: true, // or false
});
Issue an Encrypted Credential
Issue via SD-JWT secure end to end encryption
SD-JWT Secure End-to-End Encryption
SD-JWT (Selective Disclosure JSON Web Token) enables users to disclose only specific claims (pieces of data) to a relying party, while keeping the rest confidential. When combined with secure end-to-end encryption, this approach ensures that sensitive information is protected both at rest and in transit.
This implementation introduces secure encryption of the disclosures using ephemeral (one-time use) keys with the X25519 key exchange protocol and AES-256 encryption.
How It Works
1. Claim Hashing and Disclosure Generation
- Before encryption, each claim (e.g., name, birthdate, etc.) is hashed to generate its disclosure representation.
- These hashed claims are selectively shared only when the user permits it.
2. Ephemeral Key Exchange with X25519
- A fresh ephemeral key pair is generated for each encryption session using X25519, a Diffie-Hellman key exchange over Curve25519.
- These keys are one-time use only, providing forward secrecy and preventing reuse-based attacks.
- The receiver’s public key (e.g., device or backup key) is used to derive a shared secret via X25519.
3. Encryption using AES-256
- The shared secret derived from X25519 is used as the symmetric key for encrypting the disclosure payload.
- AES-256 in GCM or CBC mode (implementation-specific) is used for the encryption.
- A nonce (or IV) ensures randomness for each encryption, preventing identical cipher outputs.
A note on ephemeral key usage and backup process and functionalities
Ephemeral Key Usage (Key Backup and Recovery)
Key | Description | Purpose |
---|---|---|
device_key | Ephemeral public key derived for the current device | Used to decrypt disclosures on the current device |
back_up | Ephemeral key for user’s backup or recovery mechanism | Enables access during recovery or multi-device sync |
- These keys are included encrypted and can be safely sent over the network.
- Only the holder of the corresponding private keys can derive the shared secret and decrypt the disclosures.
Benefits
- Selective Disclosure: Users share only what’s needed.
- End-to-End Encrypted: Even intermediaries can’t read the claims.
- Forward Secrecy: Ephemeral keys ensure past sessions remain secure.
- Recovery Friendly: The
back_up
key allows for secure restoration of encrypted data.
How to Create an Encrypted SD-JWT Credential
Step 1: Define Credential Claims
const claims = {
sub: 'subject_string_here',
kyc_provider: 'DOJAH',
passport_id: '2347BV98FB',
expiry_date: new Date('10-10-2027').toISOString(),
issuanceDate: new Date().toISOString(),
first_name: 'Nelson',
last_name: 'Obioma',
issuer: { id: 'issuer string here' },
};
const disclosureFrame: Array<string> = [
'passport_id',
'expiry_date',
'first_name',
'last_name',
'issuer',
];
Step 2: Issue Encrypted SD-JWT Credential
const endUserPublicKey = 'HexadecimalEncodedEndUserPublickKey';
const result = await ezrahCredsSDK.issueEncryptedSDJWT(
claims,
disclosureFrame,
endUserPublicKey,
{
policy_control: false // default
}
);
// Response
{
_encoded: string // base64Encoded SD-JWT
urn: string, // nullable
credential: {
// SD-JWT
"header": {
"typ": "dc+sd-jwt",
"kid": "<key_id>",
"alg": "ES256K"
},
"payload": {
"iss": "did:ezrah:<issuer_did>",
"vct": "https://credentials.example.com/identity_credential",
"kyc_provider": "DOJAH",
"issuanceDate": "2025-05-15T14:23:41.174Z",
"_sd": ["...hashes"],
"_sd_alg": "sha-256"
},
"signature": "<signature_string>"
},
"encrypted_disclosures": {
"ciphertext": "...",
"iv": "...",
"ephemeralPublicKey": "..."
}
}
}
Result: Issued Credential
// response / result
{
"credential": "<jwt_string_here>"
}
This is a signed and encrypted JWT that contains secure disclosures.
Decoded JWT Structure
This is also the structure of the credential JSON response within the issueEncryptedSDJWT method.
{
"header": {
"typ": "dc+sd-jwt",
"kid": "<key_id>",
"alg": "ES256K"
},
"payload": {
"iss": "did:ezrah:<issuer_did>",
"vct": "https://credentials.example.com/identity_credential",
"kyc_provider": "DOJAH",
"issuanceDate": "2025-05-15T14:23:41.174Z",
"_sd": ["...hashes"],
"_sd_alg": "sha-256"
},
"signature": "<signature_string>"
},
"encrypted_disclosures": {
"ciphertext": "...",
"iv": "...",
"ephemeralPublicKey": "..."
}
}
Encrypted Disclosure structure
{
encrypted_disclosures: {
ciphertext: 'gCxNC18f31VAoX6Mea4fh3sdI5wDOfKUuEC9CHuVEzEcmOFY1XVPX5u21Vft2...',
iv: 'JyZ08NSSqrbLHVCt',
ephemeralPubKey: 'LZQFwtDa0eSLkpPKjKpyVYlDrMcFMYN7kPdCENhefw0',
enc: 'AES-GCM',
alg: 'X25519-AES-GCM'
}
}
Decrypted Disclosure Structure
Disclosures are decrypted on the client device.
"disclosures": [
{
"key": "passport_id",
"value": "2347BV98FB",
"salt": "...",
"_digest": "...",
"_encoded": "..."
},
{
"key": "expiry_date",
"value": "2027-10-09T23:00:00.000Z"
},
{
"key": "first_name",
"value": "Nelson"
},
{
"key": "last_name",
"value": "Obioma"
},
{
"key": "issuer",
"value": { "id": "did:ezrah:<issuer_did>" }
}
]
Behind the Scenes: Preprocessing
Before sending the request, the SDK:
- Hashes selected claims using
sha256
- Encrypts disclosures using
X25519 + AES-GCM
- Packs claims into
_sd
Example of Preprocessed Structure
{
"_hash_alg": "sha256",
"packedClaims": {
"sub": "subject_string_here",
"kyc_provider": "DOJAH",
"issuanceDate": "2025-05-15T14:23:41.207Z",
"_sd": ["<hashed_disclosure_1>", "<hashed_disclosure_2>", ...]
},
"disclosures": [
{
"key": "passport_id",
"value": "2347BV98FB",
"salt": "...",
"_digest": "...",
"_encoded": "..."
},
...
]
}
Final Credential Creation API Request
{
"subject": "did:ethr:0x1234...abcd",
"issuer": "did:ethr:0xissuer1234...def0",
"type": ["VerifiableCredential", "KYCVerifiedCredential"],
"issuanceDate": "2025-05-15T13:12:34.468Z",
"expirationDate": "2027-10-09T23:00:00.000Z"
}
OAuth Verification Model.
This section allows you define authentication verification models which use the oauth protocol pattern to allow you handle third party authentication and verification using your credentials in easy to manage flows.
const authenticationModel: VerificationModel = await ezrah.createAuthVerificationModel({
title: "Title of the verification model",
purpose: "purpose of the verification model",
claims_match: "firstname,lastname,passport_id", // claims to match, comma seperated
issuer_match: "did:ezrah:sdinsidnsdn", // if a did is entered this would be used as the issuer to match against, this always defaults to your organization did,
manual_verification: true, // set to true to get webhook notifications from these verifications.
client_id: "unique_client_id_here",
client_secret: "client_secret_here",
oob_prefix: "https://the_domain_prefix_for_oob", // this defaults to oauth.ezrah.co,
callback: "https://partner_call_back_url_for_oauth_process.",
custom_url_scheme: "url_scheme_for_mobile_clients",
session_duration: "148000" // Session duration in seconds, e.g 2 days (148000)
})
// Response
type VerificationModel = {
id: string,
verification_title: string,
purpose: string,
verification_link: string,
manual_verification: string,
issuer_match: string
claims_match: string,
client_id: string | null,
client_secret: string | null
}
Credential Verification
This section allows you to define models for verifying specific credentials. You can specify what claims to match, whether verification is manual, and then fetch all requests associated with those models. This is useful for onboarding, compliance, and access-control use cases.
Create a Verification Model
Use this method to define the conditions under which a credential should be considered valid. This can include issuer checks, field matching, and whether the request requires human review.
const model: VerificationModel = await ezrah.createVerificationModel({
title: 'Employee Verification',
purpose: 'Verify employee credentials',
claims_match: { department: 'Engineering' },
issuer_match: 'issuer123',
manual_verification: false,
});
type VerificationModel = {
id: string,
verification_title: string,
purpose: string,
verification_link: string,
manual_verification: string,
issuer_match: string
claims_match: string,
client_id: string | null,
client_secret: string | null
}
Fetch Verification Models
Retrieves a list of verification models you’ve defined. Helpful for displaying available verification flows in your dashboard or admin interface.
const models = await ezrah.verifcationModels();
Get Verification Requests
Returns all credential verification requests submitted to a specific verification model. You can use this to build review dashboards or trigger workflows based on verification outcomes.
const requests = await ezrah.verifcationRequests('model123');
DID and Templates
This section handles the discovery and templating side of the system. You can resolve DIDs to get metadata and structure your credential issuance using reusable templates.
Resolve a DID
Resolves a DID (Decentralized Identifier) and returns associated metadata. Useful for displaying user info or validating an identity before issuing or verifying credentials.
const didInfo = await ezrah.resolveDID('did:ezrah:abc123');
// sample resolve did
//
{
"did": "did:ezrah:0x7d3241B6eE2E05F09fDa3809dFA54530CE0b8fF6",
"resolvedDID": {
"didDocumentMetadata": {
"versionId": "72276059",
"updated": "2025-06-02T14:34:03Z"
},
"didResolutionMetadata": {
"contentType": "application/did+ld+json"
},
"didDocument": {
"id": "did:ezrah:0x7d3241B6eE2E05F09fDa3809dFA54530CE0b8fF6",
"verificationMethod": [
{
"id": "did:ezrah:0x7d3241B6eE2E05F09fDa3809dFA54530CE0b8fF6#controller",
"type": "EcdsaSecp256k1RecoveryMethod2020",
"controller": "did:ezrah:0x7d3241B6eE2E05F09fDa3809dFA54530CE0b8fF6",
"blockchainAccountId": "eip155:137:0x7d3241B6eE2E05F09fDa3809dFA54530CE0b8fF6"
},
{
"id": "did:ezrah:0x7d3241B6eE2E05F09fDa3809dFA54530CE0b8fF6#delegate-1",
"type": "X25519KeyAgreementKey2019",
"controller": "did:ezrah:0x7d3241B6eE2E05F09fDa3809dFA54530CE0b8fF6",
"publicKeyBase58": "F4LBhZCRzqxPYLamhZZXgZjwEEB3txfLo6TXbQZa2WQC"
}
],
"authentication": [
"did:ezrah:0x7d3241B6eE2E05F09fDa3809dFA54530CE0b8fF6#controller"
],
"assertionMethod": [
"did:ezrah:0x7d3241B6eE2E05F09fDa3809dFA54530CE0b8fF6#controller"
],
"service": [
{
"id": "did:ezrah:0x7d3241B6eE2E05F09fDa3809dFA54530CE0b8fF6#service-1",
"type": "DIDCommMessaging",
"serviceEndpoint": "https://dev-eccw.ezrah.co/webhooks/did/service/did:ezrah:0x7d3241B6eE2E05F09fDa3809dFA54530CE0b8fF6"
}
],
"keyAgreement": [
"did:ezrah:0x7d3241B6eE2E05F09fDa3809dFA54530CE0b8fF6#delegate-1"
],
"@context": [
"https://www.w3.org/ns/did/v1",
"https://w3id.org/security/suites/secp256k1recovery-2020/v2",
"https://w3id.org/security/v3-unstable"
]
}
}
}
Fetch Templates
Retrieves a list of credential templates available for use in issuance. Templates help standardize the data structures you issue, making it easier to automate workflows and comply with schema requirements.
const templates = await ezrah.templates();
Credential Analytics
Use this section to track issued credentials and gather insight into how credentials are being used. You can fetch lists of credentials and get usage stats across different timelines or templates.
Get Issued Credentials
Lists all credentials issued under your organization, optionally filtered by timeline, status, or template. Useful for analytics dashboards and credential audits.
const credentials = await ezrah.issuedCredentials({
cursor: null,
take: 10,
timeline: '05/07/2024-05/09/2025', // Previous time-RecentTime
status: 'issued',
template_id: 'template123',
});
Fetch Credential Analytics
Provides an overview of credential-related statistics, such as issuance counts and trends. Ideal for tracking adoption and performance of your identity programs.
const analytics = await ezrah.credentialAnalytics();
Webhook Management
This section lets you set up webhooks to listen for events like credential issuance or verification results. Great for real-time integrations with your backend or third-party systems.
Add a Credential Webhook
Registers a new webhook to be triggered when a specific request key is processed. Webhooks enable you to respond automatically to issuance or verification events.
const webhook = await ezrah.addCredentialsWebhook({
request_key: 'req123',
name: 'Credential Issued Webhook',
webhook_url: 'https://example.com/webhook',
});
Update a Webhook
Edits an existing webhook configuration, such as changing the endpoint URL or display name.
const updatedWebhook = await ezrah.updateCredentialWebhook({
webhook_id: 'webhook123',
request_key: 'req123',
name: 'Updated Webhook',
webhook_url: 'https://example.com/updated-webhook',
});
Delete a Webhook
Deletes a webhook by its ID. Use this to clean up old integrations or disable inactive endpoints.
const result = await ezrah.deleteCredentialWebhook('webhook123');
List Webhooks
Retrieves all currently registered webhooks. Useful for building settings pages or debugging integrations.
const webhooks = await ezrah.webhooks();
Organization Management
Manage your organization settings such as general metadata and branding. These APIs help ensure your credentials are visually aligned with your brand and that team access is correctly configured.
Get Organization Info
Returns information about the current organization using the SDK. This includes your organization’s name, branding, and configuration details.
const orgDetails = await ezrah.organization();
Request Mediator
This functionality set allows you to be able to send DIDComm Requests to partner DIDs in a customizable manner, you can also include other protocol request attachments within your requests to enable partner dids initiate integrated calls for different interactions and processes.
// Send a notification message to a did
const result = await ezrah.createRequestMessage({
source: "Partner X",
oob_code: "eyJ3f32b298fdbdf9egf0gb3fb8-de29e9vfff22ff.....",
message: "Partner X is trying to access your passport",
reciever_did: "did:ezrah:0x9cdac82d.....",
session_code: "session tracker for the individual request"
})
// Result is boolean
// result = true/false
The session_code
in the request would be used passed through the protocol processes and made available at the webhooks and callback urls to detect the active session the request belongs to.
Error Handling
To ensure your integration is resilient, wrap all SDK methods in try/catch blocks. This helps you gracefully handle network issues, misconfigurations, or invalid inputs.
try {
const response = await ezrah.templates();
} catch (error) {
console.error('Something went wrong:', error);
}
Notes
- Fully written in TypeScript with complete type definitions.
- Designed to work hand-in-hand with the Ezrah GraphQL Playground for advanced operations.
- For security, always store your API keys using environment variables or a secure vault.