Skip to main content

Overview

The SdJwtVcApi provides methods for working with SD-JWT (Selective Disclosure JWT) Verifiable Credentials, enabling privacy-preserving credentials where holders can selectively disclose claims.
const sdJwt = await agent.sdJwtVc.sign({
  holder: { method: 'did', didUrl: holderDid },
  payload: {
    vct: 'https://example.com/credentials/employee',
    name: 'Alice Smith',
    email: '[email protected]',
  },
})

Methods

sign()

Create and sign an SD-JWT Verifiable Credential.
const result = await agent.sdJwtVc.sign({
  holder: {
    method: 'did',
    didUrl: holderDid,
  },
  issuer: {
    method: 'did',
    didUrl: issuerDid,
  },
  payload: {
    vct: 'https://example.com/credentials/identity',
    given_name: 'Alice',
    family_name: 'Smith',
    email: '[email protected]',
    age: 30,
    address: {
      street: '123 Main St',
      city: 'Springfield',
    },
  },
  disclosureFrame: {
    _sd: ['given_name', 'family_name', 'email', 'age', 'address'],
  },
})

const compact = result.compact
options.holder
object
required
Holder binding configuration
  • method: ‘did’ or ‘jwk’
  • didUrl: DID URL for holder (if method is ‘did’)
  • jwk: JWK for holder (if method is ‘jwk’)
options.issuer
object
Issuer configuration. Defaults to agent’s default issuer.
  • method: ‘did’ or ‘x5c’
  • didUrl: DID URL for issuer
options.payload
SdJwtVcPayload
required
The credential payload including:
  • vct: Verifiable Credential Type (required)
  • Additional claims
options.disclosureFrame
object
Frame specifying which claims should be selectively disclosable
Returns: Promise<{ compact: string, sdJwtVc: SdJwtVc, header: SdJwtVcHeader, payload: SdJwtVcPayload }>

present()

Create a presentation with selective disclosure from an SD-JWT VC.
const presentation = await agent.sdJwtVc.present({
  sdJwtVc: receivedSdJwtVc,
  disclosureFrame: {
    given_name: true,
    family_name: true,
    age: true,
    // email and address not disclosed
  },
  holderBinding: {
    method: 'did',
    didUrl: holderDid,
    audience: verifierDid,
    nonce: 'verifier-nonce-123',
  },
})
options.sdJwtVc
string | SdJwtVc
required
The SD-JWT VC to present (compact format or parsed object)
options.disclosureFrame
object
required
Object specifying which claims to disclose (true = disclose, false = hide)
options.holderBinding
object
Holder binding configuration for key binding JWT:
  • method: ‘did’ or ‘jwk’
  • didUrl: Holder DID URL
  • audience: Verifier identifier
  • nonce: Challenge from verifier
Returns: Promise<string> - Presentation in compact format

verify()

Verify an SD-JWT VC or presentation.
const result = await agent.sdJwtVc.verify({
  sdJwtVc: presentation,
  keyBinding: {
    audience: verifierDid,
    nonce: 'verifier-nonce-123',
  },
  requiredClaimFrame: {
    given_name: true,
    age: true,
  },
})

if (result.verification.verified) {
  console.log('Verified!')
  console.log('Issuer:', result.verification.issuerId)
  console.log('Holder:', result.verification.holderId)
  console.log('Payload:', result.payload)
}
options.sdJwtVc
string
required
SD-JWT VC or presentation in compact format
options.keyBinding
object
Expected key binding values:
  • audience: Expected audience
  • nonce: Expected nonce
options.requiredClaimFrame
object
Claims that must be disclosed for verification to succeed
Returns: Promise<SdJwtVcVerificationResult> Result contains:
  • verification: Verification result with verified boolean, issuerId, holderId
  • payload: Disclosed payload
  • header: JWT header

fromCompact()

Parse an SD-JWT VC from compact format.
const sdJwtVc = agent.sdJwtVc.fromCompact(
  'eyJhbGc...~WyJz...~eyJhbGc...'
)

console.log('Header:', sdJwtVc.header)
console.log('Payload:', sdJwtVc.payload)
console.log('Disclosures:', sdJwtVc.disclosures)
sdJwtVcCompact
string
required
SD-JWT VC in compact format
Returns: SdJwtVc<Header, Payload>

fetchTypeMetadata()

Fetch type metadata for the vct (Verifiable Credential Type).
const sdJwtVc = agent.sdJwtVc.fromCompact(compact)

const metadata = await agent.sdJwtVc.fetchTypeMetadata(sdJwtVc, {
  throwErrorOnFetchError: false,
})

if (metadata) {
  console.log('Schema:', metadata.schema)
  console.log('Rendering:', metadata.rendering)
}
sdJwtVc
SdJwtVc
required
Parsed SD-JWT VC object
options.throwErrorOnFetchError
boolean
default:"true"
Whether to throw error if metadata cannot be fetched
options.throwErrorOnUnsupportedVctValue
boolean
default:"true"
Whether to throw error if vct value is not supported
Returns: Promise<ResolvedTypeMetadata | undefined>

store()

Store an SD-JWT VC in the wallet.
const record = await agent.sdJwtVc.store({
  sdJwtVc: compact,
})

console.log('Stored with ID:', record.id)
options.sdJwtVc
string
required
SD-JWT VC in compact format
Returns: Promise<SdJwtVcRecord>

getById()

Retrieve a stored SD-JWT VC by ID.
const record = await agent.sdJwtVc.getById(recordId)
console.log('SD-JWT:', record.compactSdJwtVc)
id
string
required
Record ID
Returns: Promise<SdJwtVcRecord>

getAll()

Retrieve all stored SD-JWT VCs.
const records = await agent.sdJwtVc.getAll()
console.log(`Found ${records.length} SD-JWT VCs`)
Returns: Promise<SdJwtVcRecord[]>

findAllByQuery()

Find SD-JWT VCs by query.
const records = await agent.sdJwtVc.findAllByQuery(
  { vct: 'https://example.com/credentials/employee' },
  { limit: 10 }
)
query
Query<SdJwtVcRecord>
required
Query object
queryOptions
QueryOptions
Query options (limit, offset)
Returns: Promise<SdJwtVcRecord[]>

deleteById()

Delete a stored SD-JWT VC by ID.
await agent.sdJwtVc.deleteById(recordId)
id
string
required
Record ID
Returns: Promise<void>

update()

Update a stored SD-JWT VC record.
const record = await agent.sdJwtVc.getById(recordId)
record.metadata.set('custom', 'value')

await agent.sdJwtVc.update(record)
sdJwtVcRecord
SdJwtVcRecord
required
Updated record
Returns: Promise<void>

Example Usage

import { Agent } from '@credo-ts/core'

// Issuer creates SD-JWT VC
const { compact } = await agent.sdJwtVc.sign({
  holder: {
    method: 'did',
    didUrl: holderDid,
  },
  issuer: {
    method: 'did',
    didUrl: issuerDid,
  },
  payload: {
    vct: 'https://example.com/identity',
    given_name: 'Alice',
    family_name: 'Smith',
    email: '[email protected]',
    birthdate: '1990-01-01',
    address: {
      street: '123 Main St',
      city: 'Springfield',
    },
  },
  disclosureFrame: {
    _sd: ['given_name', 'family_name', 'email', 'birthdate', 'address'],
  },
})

// Holder stores credential
const record = await agent.sdJwtVc.store({ sdJwtVc: compact })

// Holder creates selective disclosure presentation
const presentation = await agent.sdJwtVc.present({
  sdJwtVc: compact,
  disclosureFrame: {
    given_name: true,  // Disclose
    family_name: true, // Disclose
    email: false,      // Hide
    birthdate: false,  // Hide
    address: false,    // Hide
  },
  holderBinding: {
    method: 'did',
    didUrl: holderDid,
    audience: verifierDid,
    nonce: verifierNonce,
  },
})

// Verifier verifies presentation
const result = await agent.sdJwtVc.verify({
  sdJwtVc: presentation,
  keyBinding: {
    audience: verifierDid,
    nonce: verifierNonce,
  },
  requiredClaimFrame: {
    given_name: true,
    family_name: true,
  },
})

if (result.verification.verified) {
  console.log('Verified! Disclosed claims:', result.payload)
  // Only given_name and family_name are in result.payload
}

Privacy Benefits

SD-JWT VCs enable:
  1. Selective Disclosure: Holders reveal only necessary claims
  2. Unlinkability: Different presentations can’t be linked to same credential
  3. Holder Binding: Cryptographic proof that presenter is the holder
  4. Minimal Disclosure: Satisfy verifier requirements with minimal information
// Only disclose name for account creation
const accountPresentation = await agent.sdJwtVc.present({
  sdJwtVc: identityCredential,
  disclosureFrame: { given_name: true, family_name: true },
})

// Only disclose age>=18 for age verification
const agePresentation = await agent.sdJwtVc.present({
  sdJwtVc: identityCredential,
  disclosureFrame: { birthdate: true },
})

// These presentations cannot be correlated

Build docs developers (and LLMs) love