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:

Always test present through portal2.demo.walt.id.


How Presentation Works

Loading diagram...

  1. Preview the request to resolve verifier metadata, response encryption, DCQL matches, and transaction data.
  2. Show the verifier name, the claims that will be shared, and any response-encryption state.
  3. Submit the holder's selection, or reject the request. Omitting an error on reject sends access_denied for 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.

Kotlin
Swift
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

Last updated on September 29, 2026