Presenting Credentials via OID4VP
This guide shows you how to present a verifiable credential from the walt.id Wallet SDK using OID4VP 1.0 with DCQL for matching. You hand the wallet a presentation request — typically an openid4vp:// URL from Portal2 — and the wallet finds matching credentials, builds a presentation, and submits it.
OID4VP: The protocol used to deliver a presentation from the wallet to the verifier.
DCQL: The query language the verifier uses to describe which credentials and claims it needs.
Presentation is preview → consent → submit or reject. Isolated steps keep the SDK from sending anything until the holder approves. For in-person mdoc sharing, use Proximity Sharing instead of an OID4VP URL.
Prerequisites
Before you begin, ensure you have:
- A wallet that already holds a matching credential — Receive one first with Receiving Credentials via OID4VCI or a sample app.
- A presentation request — Create one in portal2.demo.walt.id, or follow a Verifier2 guide such as SD-JWT VC via OID4VP.
Always test present through portal2.demo.walt.id.
How Presentation Works
Loading diagram...
- Preview the request to resolve verifier metadata, response encryption, DCQL matches, and transaction data.
- Show the verifier name, the claims that will be shared, and any response-encryption state.
- Submit the holder's selection, or reject the request. Omitting an error on reject sends
access_deniedfor a valid request.
Preview and Submit
The same session APIs work for SD-JWT VC, W3C VC, and ISO 18013-5 mDL. Preview currently covers signed requests, encrypted responses, and OpenID4VP transaction data.
when (val result = wallet.previewPresentation(requestUrl)) {
is MobileWalletPresentationPreviewResult.Invalid -> {
showRequestError(result.message)
wallet.rejectPresentation(result.previewHandle)
}
is MobileWalletPresentationPreviewResult.Ready -> {
val preview = result.preview
preview.request.verifierMetadata?.display?.name?.let(::showVerifierName)
when (val encryption = preview.request.responseEncryption) {
MobileWalletResponseEncryption.NotRequired -> showPlainResponseNotice()
is MobileWalletResponseEncryption.Required -> showEncryptedResponseNotice(
algorithm = encryption.keyManagementAlgorithm,
contentEncryption = encryption.contentEncryptionAlgorithm,
verifierKeyId = encryption.verifierKeyId,
verifierKeyThumbprint = encryption.verifierKeyThumbprint,
)
}
val outcome = wallet.submitPresentation(
previewHandle = preview.previewHandle,
selectedCredentialOptions = preview.credentialOptions.map {
MobileWalletPresentationCredentialSelection(
queryId = it.queryId,
credentialId = it.credentialId,
)
},
did = identity.did,
)
}
}
Response-encryption metadata describes protection of the authorization response. It does not establish verifier trust and does not expose verifier key material.
🎉 You've presented a credential to the verifier.
Selective Disclosure and Transaction Data
The verifier asks for claims through the claims array of its DCQL query. Preview returns required and selectable claims so your UI can show exactly what will be shared.
When the request includes OpenID4VP transaction_data, pass the profile types your app understands in wallet configuration. Unknown types are rejected before submit. Profile fields stay available for UI.
Next Steps
- Share an mdoc in person — Proximity Sharing.
- Present through the OS picker — Digital Credentials API.
- Configure signing policy and reader trust — Security.
