Overview
Credo supports multiple presentation and proof formats across different APIs:
- W3C Presentations: Via
agent.w3cCredentials for W3C Verifiable Presentations
- SD-JWT Presentations: Via
agent.sdJwtVc for selective disclosure
- DIDComm Proofs: Via
agent.didcomm.proofs for DIDComm proof protocols
W3C Verifiable Presentations
See W3cCredentialsApi for complete documentation.
Creating a Presentation
const presentation = await agent.w3cCredentials.createPresentation({
credentials: [credential1, credential2],
holder: holderDid,
})
const { signedPresentation } = await agent.w3cCredentials.signPresentation({
format: ClaimFormat.JwtVp,
presentation,
challenge: verifierChallenge,
verificationMethod: `${holderDid}#key-1`,
})
Verifying a Presentation
const result = await agent.w3cCredentials.verifyPresentation({
presentation: signedPresentation,
challenge: verifierChallenge,
domain: 'https://verifier.example.com',
})
if (result.verified) {
console.log('Presentation verified')
console.log('Credential results:', result.credentialResults)
}
SD-JWT Presentations
SD-JWT supports selective disclosure, allowing holders to reveal only specific claims.
Creating an SD-JWT Presentation
import { SdJwtVcApi } from '@credo-ts/core'
// Holder creates presentation with selected disclosures
const presentation = await agent.sdJwtVc.present({
sdJwtVc: receivedSdJwtVc,
// Only disclose specific claims
disclosureFrame: {
name: true,
age: true,
// address is not disclosed
},
// Optional holder binding
holderBinding: {
method: 'did',
didUrl: holderDid,
audience: verifierDid,
nonce: verifierNonce,
},
})
Parameters:
The received SD-JWT VC compact format
Object specifying which claims to disclose
Holder binding configuration for key binding
Returns: Promise<string> - SD-JWT presentation in compact format
Verifying an SD-JWT Presentation
const result = await agent.sdJwtVc.verify({
sdJwtVc: presentation,
keyBinding: {
audience: verifierDid,
nonce: verifierNonce,
},
requiredClaimFrame: {
name: true,
age: true,
},
})
if (result.verification.verified) {
console.log('SD-JWT presentation verified')
console.log('Disclosed claims:', result.payload)
}
See SdJwtVcApi for complete documentation.
DIDComm Proof Protocol
DIDComm provides a complete proof request/presentation protocol for connection-based verification.
Requesting a Proof (Verifier)
// Request proof from holder
const proofRecord = await agent.didcomm.proofs.requestProof({
connectionId: connectionId,
protocolVersion: 'v2',
proofFormats: {
anoncreds: {
name: 'Proof Request',
version: '1.0',
requested_attributes: {
name: {
name: 'name',
restrictions: [{ schema_id: schemaId }],
},
},
requested_predicates: {
age: {
name: 'age',
p_type: '>=',
p_value: 18,
},
},
},
},
})
Accepting Proof Request (Holder)
// Get available credentials for request
const credentials = await agent.didcomm.proofs.getCredentialsForRequest({
proofExchangeRecordId: proofRecord.id,
})
// Select credentials
const selectedCredentials = await agent.didcomm.proofs.selectCredentialsForRequest({
proofExchangeRecordId: proofRecord.id,
})
// Accept request and send presentation
const updatedRecord = await agent.didcomm.proofs.acceptRequest({
proofExchangeRecordId: proofRecord.id,
proofFormats: selectedCredentials.proofFormats,
})
Verifying Proof (Verifier)
// Accept the presentation
const finalRecord = await agent.didcomm.proofs.acceptPresentation({
proofExchangeRecordId: proofRecord.id,
})
// Get format-specific data
const formatData = await agent.didcomm.proofs.getFormatData(
proofRecord.id
)
if (finalRecord.state === DidCommProofState.Done) {
console.log('Proof verified successfully')
}
Presentation Exchange (DIF)
For Presentation Exchange v2 support, use OpenID4VC:
// Verifier creates authorization request
const { authorizationRequest } = await agent.openid4vc.verifier.createRequest({
requestSigner: {
method: 'did',
didUrl: verifierDid,
},
presentationExchange: {
definition: presentationDefinition, // DIF PE definition
},
})
// Holder resolves and responds
const resolved = await agent.openid4vc.holder.resolveAuthorizationRequest(
authorizationRequest
)
const credentials = await agent.openid4vc.holder.getCredentialsForRequest({
resolvedAuthorizationRequest: resolved,
})
const response = await agent.openid4vc.holder.acceptRequest({
resolvedAuthorizationRequest: resolved,
credentials: selectedCredentials,
})
// Verifier verifies response
const verification = await agent.openid4vc.verifier.verifyResponse({
authorizationResponse: response,
})
Common Patterns
Challenge-Response Pattern
Most presentation protocols use a challenge (nonce) for replay protection:
// Verifier generates challenge
const challenge = crypto.randomUUID()
// Holder signs presentation with challenge
const presentation = await agent.w3cCredentials.signPresentation({
// ...
challenge,
})
// Verifier checks challenge
const result = await agent.w3cCredentials.verifyPresentation({
presentation,
challenge, // Must match
})
Selective Disclosure
Only reveal necessary information:
// SD-JWT: Select specific claims
const presentation = await agent.sdJwtVc.present({
sdJwtVc,
disclosureFrame: {
name: true, // Disclose name
age: true, // Disclose age
address: false, // Keep address private
},
})
// DIDComm: Request only needed attributes
const proofRecord = await agent.didcomm.proofs.requestProof({
// ...
proofFormats: {
anoncreds: {
requested_attributes: {
// Only request name, not full credential
name: { name: 'name' },
},
requested_predicates: {
// Use predicate to prove age >= 18 without revealing exact age
age: { name: 'age', p_type: '>=', p_value: 18 },
},
},
},
})
See Also