Skip to main content

OpenID4VCI and OpenID4VP

A wallet uses two protocols from the OpenID for Verifiable Credentials family:

  • OpenID for Verifiable Credential Issuance (OpenID4VCI) to receive credentials from issuers
  • OpenID for Verifiable Presentations (OpenID4VP) to present credentials to verifiers

To do both, configure and enable at least one instance of each: an OpenID4VCI instance in issuanceProtocol and an OpenID4VP instance in verificationProtocol. This page explains how to configure them for a wallet.

Example configuration​

issuanceProtocol:
OPENID4VCI_FINAL1:
display: "exchange.openIdFinal1"
order: 1
type: "OPENID4VCI_FINAL1"
params:
private:
encryption: "<32-byte hex>"
nonce:
signingKey: "<32-byte hex>"
verificationProtocol:
OPENID4VP_FINAL1:
display: "exchange.openid4vpFinal1"
order: 1
type: "OPENID4VP_FINAL1"
params:
public:
holder:
supportedClientIdSchemes:
[
redirect_uri,
verifier_attestation,
decentralized_identifier,
x509_san_dns,
x509_hash,
]

The sections below explain each part of this configuration, along with optional features such as DPoP, the Authorization Code Flow, and transaction data.

Receiving credentials with OpenID4VCI​

Enable OpenID4VCI​

Configure at least one enabled instance of type OPENID4VCI_FINAL1 in the issuanceProtocol object. See the issuance protocols reference for all options.

Keys​

Each OpenID4VCI instance needs its own keys:

  • encryption: Encrypts the access and refresh tokens the wallet receives from issuers. If you change this key, stored tokens can no longer be used. Credentials already held continue to work, but they can no longer be refreshed and new batches cannot be requested.
  • nonce.signingKey: Signs nonces when Core issues credentials. Required for every instance, even if you only use Core as a wallet.

Keys are 32-byte hex strings. Supply them as environment variables rather than in configuration files. See Secrets and Keys for details.

DPoP​

Some issuers require Demonstrating Proof of Possession (DPoP), which binds the access tokens they issue to a key held by the wallet. To support DPoP, set holderDpopKeyStorage to the name of a configured key storage provider. The wallet uses that provider to generate its DPoP proofs.

issuanceProtocol:
OPENID4VCI_FINAL1:
params:
public:
holderDpopKeyStorage: "<key storage instance>"

If holderDpopKeyStorage is not configured, the wallet does not support DPoP and cannot receive credentials from issuers that require it.

Authorization Code Flow​

When an issuer offers credentials using the Authorization Code Flow, the wallet identifies itself to the issuer with a client ID. Add an entry to the root-level credentialIssuer object for each issuer you want to accept these offers from, with the client ID the wallet should use:

credentialIssuer:
EUDI_PID_FLOW:
display:
en: "EUDI Issuer"
de: "EUDI Issuer"
order: 1
enabled: true
params:
public:
logo: "<logo>"
issuer: "https://issuer.eudiw.dev"
private:
clientId: "my-wallet-id"

URL scheme​

By default, the wallet accepts credential offers using the openid-credential-offer URL scheme, as specified in the OpenID4VCI standard.

To accept offers using a custom scheme, configure an additional OpenID4VCI instance and set its urlScheme parameter. When the wallet receives a credential offer, it uses the instance that handles that offer's scheme.

Rejecting credential offers​

When a holder rejects a credential offer, the wallet can generate a temporary identifier for the rejection. To enable this, set both:

  • rejectionIdentifier.didMethod: The DID method to use, by configuration instance name.
  • rejectionIdentifier.keyAlgorithm: The key algorithm to use, by configuration instance name, for example ECDSA.

Presenting credentials with OpenID4VP​

Enable OpenID4VP​

Configure at least one enabled instance of type OPENID4VP_FINAL1 in the verificationProtocol object. See the verification protocols reference for all options.

Client Identifier Schemes​

Client Identifier Schemes (called "Client Identifier Prefixes" in OpenID4VP 1.0) define how the wallet validates the identity of a verifier. When a verifier sends a proof request, its scheme determines how the wallet checks that the request is legitimate.

Schemes provide different levels of trust assurance. For example, redirect_uri provides no cryptographic verification of the verifier's identity, while x509_san_dns requires the verifier to prove control of a domain through certificate validation.

Use holder.supportedClientIdSchemes to set which schemes the wallet accepts. The wallet rejects proof requests that use any other scheme.

For OPENID4VP_FINAL1, use decentralized_identifier for DID-based verifiers. It replaces the did scheme used in earlier drafts.

note

For all supported schemes, see the verification protocols reference.

Transaction data​

OpenID4VP lets a verifier attach transaction_data to a proof request: details of a transaction, such as a document to sign or a payment to confirm, that the holder must review and approve before presenting a credential. The holder's approval is then bound to the presentation.

To handle these requests, configure at least one provider in the root-level transactionDataProvider object. When a request arrives, the wallet uses the provider that supports the request's transaction data type, and fails the invitation if none does. For the supported provider types, see the configuration reference. For the full holder flow, see Transaction Authorization for Wallets.

Display parameters​

Every provider requires transactionDataDisplayParams, which controls how transaction data is turned into human-readable blocks for the holder to review. The wallet returns these blocks as transactionDataDisplay when you fetch a transaction data entry.

  • groupPath: JSONPath selecting what to render as separate blocks. An array produces one block per element; an object or the root $ produces a single block. If nothing matches, the result is an empty list.
  • titlePath: Optional. JSONPath, relative to each block, selecting the value used as the block's title.
  • attributes: The values to display in each block. Each entry pairs a path (JSONPath, relative to each block) with a display label, which becomes the key in the key-value pairs returned to the wallet. If a path doesn't resolve for a block, that attribute is left out of the block.

These paths are evaluated against the transaction data as it is sent over the wire. For QES_APPROVAL, this means one titled block per document:

transactionDataProvider:
QES_APPROVAL:
type: QES_APPROVAL
display:
en: "QES transaction data"
order: 1
enabled: true
params:
public:
transactionDataDisplayParams:
groupPath: "$.documentInfos[*]"
titlePath: "$.label"
attributes:
- path: "$.access.oneTimePassword"
display: "transactionData.qesApproval.documentInfo.access.oneTimePassword"
- path: "$.href"
display: "transactionData.qesApproval.documentInfo.href"
- path: "$.checksum"
display: "transactionData.qesApproval.documentInfo.checksum"
- path: "$.signed_props"
display: "transactionData.qesApproval.documentInfo.signedProps"

The SCA types use snake_case field names nested under a payload wrapper, so they use groupPath: "$.payload" to produce a single untitled block per entry:

transactionDataProvider:
SCA_PAYMENT_CONFIRMATION:
type: SCA_PAYMENT_CONFIRMATION
display:
en: "Payment confirmation"
order: 2
enabled: true
params:
public:
leewaySeconds: 60
transactionDataDisplayParams:
groupPath: "$.payload"
attributes:
- path: "$.payee.name"
display: "transactionData.scaPaymentConfirmation.payee.name"
- path: "$.execution_date"
display: "transactionData.scaPaymentConfirmation.executionDate"

Leeway for SCA types​

All SCA provider types also require leewaySeconds, which sets how far in the past an executionDate can be and still be accepted as not yet past. QES_APPROVAL does not use it.

Presenting ISO mdocs​

ISO 18013-7 defines its own flavor of OpenID4VP for presenting mdocs, with a different URL scheme and Client Identifier Scheme. To support it, configure a second OpenID4VP instance:

verificationProtocol:
MDOC_OPENID4VP:
display: "exchange.mdocOpenid"
order: 2
type: "OPENID4VP_FINAL1"
params:
public:
urlScheme: mdoc-openid4vp
holder:
supportedClientIdSchemes: [x509_san_dns]
  • urlScheme: Set to mdoc-openid4vp, as specified in ISO 18013-7. The wallet uses this instance for any proof request with this scheme. Instances use openid4vp by default.
  • holder.supportedClientIdSchemes: Set x509_san_dns as the only scheme, as specified in ISO 18013-7.

Query language​

Verifiers using OpenID4VP 1.0 describe the credentials they want with the Digital Credentials Query Language (DCQL). DCQL support requires no configuration. For the DCQL features the wallet supports, see Submitting a Presentation.