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.
- To configure issuance, see OpenID4VCI
- To configure verification, see OpenID4VP
- For every supported parameter, see the configuration reference.
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 exampleECDSA.
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.
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 apath(JSONPath, relative to each block) with adisplaylabel, which becomes thekeyin 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 tomdoc-openid4vp, as specified in ISO 18013-7. The wallet uses this instance for any proof request with this scheme. Instances useopenid4vpby default.holder.supportedClientIdSchemes: Setx509_san_dnsas 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.