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
Holder binding configuration
method: ‘did’ or ‘jwk’
didUrl: DID URL for holder (if method is ‘did’)
jwk: JWK for holder (if method is ‘jwk’)
Issuer configuration. Defaults to agent’s default issuer.
method: ‘did’ or ‘x5c’
didUrl: DID URL for issuer
The credential payload including:
vct: Verifiable Credential Type (required)
- Additional claims
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',
},
})
The SD-JWT VC to present (compact format or parsed object)
Object specifying which claims to disclose (true = disclose, false = hide)
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)
}
SD-JWT VC or presentation in compact format
Expected key binding values:
audience: Expected audience
nonce: Expected nonce
options.requiredClaimFrame
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)
SD-JWT VC in compact format
Returns: SdJwtVc<Header, Payload>
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)
}
options.throwErrorOnFetchError
Whether to throw error if metadata cannot be fetched
options.throwErrorOnUnsupportedVctValue
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)
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)
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
Query options (limit, offset)
Returns: Promise<SdJwtVcRecord[]>
deleteById()
Delete a stored SD-JWT VC by ID.
await agent.sdJwtVc.deleteById(recordId)
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)
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:
- Selective Disclosure: Holders reveal only necessary claims
- Unlinkability: Different presentations can’t be linked to same credential
- Holder Binding: Cryptographic proof that presenter is the holder
- 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