Skip to main content
Didit Raises $7.5M to Build the Infrastructure for Identity and Fraud
Didit
Back to blog
Blog · October 6, 2026

OpenID4VP verifier guide: accepting the EUDI Wallet

How an OpenID4VP verifier works for the EUDI Wallet: request objects, DCQL queries, response modes, SD-JWT VC and mdoc checks, the HAIP rules in EU law, common mistakes and where to test.

Alberto Rosas, co-founder and CEO of DiditBy Alberto RosasCo-founder & CEO, DiditUpdated
openid4vp-verifier-cover.png

In short

OpenID4VP (OpenID for Verifiable Presentations) is the protocol a verifier uses to ask a digital wallet for credentials and get a signed presentation back. Version 1.0 became an OpenID Final Specification on 10 July 2025, and the EU Digital Identity (EUDI) Wallet uses it for remote presentation.[2][3]

  • You send a signed request with a DCQL query; the wallet returns a VP Token.
  • You verify the issuer signature, disclosures, key binding and revocation yourself.
  • For the EUDI Wallet, EU law adds certificate and registration rules.

Last reviewed: 5 October 2026 · Not legal advice

OpenID4VP is how a website or app asks a wallet to prove something about a person, such as a name or a date of birth. The verifier says which credentials and claims it wants, the user approves in the wallet, and the wallet returns a presentation the verifier checks cryptographically. In the specification's own words, it "defines a protocol for requesting and presenting Credentials".[1]

This guide is for developers building an OpenID4VP verifier for the EUDI Wallet: the request object, DCQL, response modes, device flows, SD-JWT VC and mdoc checks, the HAIP rules in EU law, common mistakes and where to test.

OpenID4VP in plain words

OpenID4VP reuses the shape of an OAuth 2.0 authorization request. The verifier asks for the response type vp_token, and a successful response must include a vp_token parameter carrying the presentations.[1] There is no code or access token to exchange: the data arrives in the response.

The wallet authenticates the relying party, checks it asks for no more than it registered, collects the user's approval and signs the presentation. The relying party then verifies the issuer signature, the revocation status and the device binding.[3] The person identification data (PID) is issued in two formats, SD-JWT VC and ISO/IEC mdoc, and both use salted hashes so the user can share some attributes and hide the rest.[5][3]

  1. 10 July 2025Final specOpenID4VP 1.0 approved.
  2. 22 July 2026PublishedCIR 2026/1731 (adopted 15 July 2026) in the Official Journal.
  3. 23 July 2026ARF v3.0.0Current architecture release.
  4. 24 December 2026WalletsAt least one per Member State.
  5. 24 December 2027AcceptanceRegulated private relying parties.

From final specification to the private-sector acceptance date.[2][3][4][5]

How an OpenID4VP verifier exchange works

OpenID4VP publishes a reference design for the response mode direct_post, where the wallet posts the response to a server endpoint instead of sending it through the browser.[1]

User browser Verifier frontend Response endpoint Wallet
1Starts verification
2Open transaction
3Transaction and request ids
4Request with nonce, DCQL

Wallet checks the verifier, user consents

5POST VP Token, state
6Redirect with response code
7Back to the site
8Fetch with code
9VP Token

The direct_post reference design in OpenID4VP 1.0, section 13.3, simplified.[1]

  • Generate a nonce of "at least 16 fresh, cryptographically random bytes" per request.
  • Send the request-id from the response endpoint to the wallet as state.
  • Return a redirect URI with a fresh response_code once the wallet posts.
  • Fetch the VP Token with the transaction-id and that code, then check the nonce.

The response_code blocks session fixation, where an attacker relays your request to a victim's wallet. The specification notes it does not help across devices and recommends extra mechanisms there.[1]

An OpenID4VP presentation from an EUDI Wallet, start to finish.

The OpenID4VP request object and client identifiers

The client_id starts with a Client Identifier Prefix that tells the wallet how to authenticate the verifier.[1] Large requests travel by reference: the wallet fetches the signed request object from a request_uri. For QR codes, the specification recommends direct_post with request_uri, since the request "might not fit in a QR code".[1]

PrefixHow the wallet authenticates the verifierSigned request
redirect_uriThe identifier is the redirect or response URICannot be signed
x509_san_dnsDNS name in the leaf certificate's SANRequired
x509_hashSHA-256 hash of the leaf certificateRequired
decentralized_identifierKey from the DID DocumentRequired
verifier_attestationAttestation JWT from an issuer the wallet trustsRequired
openid_federationFederation trust chainPer OpenID Federation

Client Identifier Prefixes, OpenID4VP 1.0 section 5.9.[1]

For EUDI verifiers, EU law picks the prefix: the leaf certificate "for use with the x509_hash Client Identifier Prefix shall be a RP access certificate as specified in ETSI TS 119 475", and one element of verifier_info "shall include the registration certificate".[5]

DCQL queries: ask for what you registered

The Digital Credentials Query Language (DCQL) is the JSON query that names the credentials and claims you want. It holds a required credentials array and an optional credential_sets array; each credential query needs an id, a format and a meta object.[1] The specification's SD-JWT VC example:[1]

{ "credentials": [ { "id": "my_credential", "format": "dc+sd-jwt", "meta": { "vct_values": [ "https://credentials.example.com/identity_credential" ] }, "claims": [ {"path": ["last_name"]}, {"path": ["first_name"]}, {"path": ["address", "street_address"]} ] } ] }

For an mdoc, the format is mso_mdoc and meta carries a doctype_value.[1] For the PID, swap in its type and claim names; the mandatory PID attributes are family name, given name, birth date, birth place and nationality.[7]

  • require_cryptographic_holder_binding defaults to true. Keep it: it makes the wallet return a key binding proof.[1]
  • trusted_authorities only filters what the wallet offers. Verifiers "must verify that the issuer of a received presentation is trusted on their own".[1]
  • Relying parties "shall not request users to provide any data other than" what they registered, and the wallet checks.[4][3]

OpenID4VP response modes

The response mode decides how the VP Token travels back. The default for vp_token is fragment, in the fragment of the redirect URI.[1]

Response modeWhere the VP Token goesEncrypted
fragmentRedirect URI fragment, through the browserNo
direct_postHTTP POST to the response_uriNo
direct_post.jwtHTTP POST of an encrypted JWTYes
dc_apiBack through the Digital Credentials APINo
dc_api.jwtSame, encryptedYes

Response modes in OpenID4VP 1.0.[1]

With direct_post, response_uri is required and redirect_uri must be absent, or the wallet returns invalid_request.[1] Moldova's EVO Wallet, for example, documents OpenID4VP 1.0 with direct_post.jwt in a same-device flow, ISO/IEC 18013-5 mdoc profiled per OpenID4VC HAIP 1.0, and an IETF Token Status List for revocation.[11]

Same-device, cross-device and the Digital Credentials API

The ARF lists the supported remote combinations: OpenID4VP combined with a transmission mechanism based on redirects and custom URI schemes; OpenID4VP or ISO/IEC 18013-7 combined with the W3C Digital Credentials API; and, optionally, ISO/IEC 18013-7 with redirects and custom URI schemes.[3]

Same device

Custom URI scheme

  • The browser hands openid4vp:// to the operating system
  • The wallet opens on the same phone

ARF 4.4.3.1

Cross device

QR code

  • The desktop shows a QR code to scan
  • Open to phishing and relay

ARF 4.4.3.1

Browser API

Digital Credentials API

  • The browser passes the verified origin
  • Enabled by default in Chrome 141

OpenID4VP Appendix A

Three ways a wallet receives an OpenID4VP request.[3][1][10]

The ARF says custom URI schemes are "not recommended for cross-device flows" and names the Digital Credentials API as the alternative.[3] Over the API, the wallet learns the verifier's origin as authenticated by the browser, "which is important for phishing resistance".[1] The W3C specification is still a draft.[9] What the user sees on a phone:

Browser: example.com

Verify your identity

This website asks your wallet for your details.

1The browser sends an openid4vp:// URI to the operating system.[3]

EUDI Wallet

Checking the request

The wallet opens and connects to the relying party.

2The wallet authenticates the relying party and checks what it registered.[3]

EUDI Wallet

Choose what to share

  • Family nameShared
  • Birth dateShared
  • AddressNot shared

Share

3The user approves the attributes.[3]

Browser: example.com

Details received

4The wallet posts and returns the user.[1]

Verifying an SD-JWT VC presentation step by step

An SD-JWT VC presentation carries the issuer-signed JWT, the disclosures the user revealed and a Key Binding JWT. The verifier "MUST validate every individual Verifiable Presentation" and reject any with the wrong nonce.[1]

1Verify the issuer signature

The key chains to a trusted PID or attestation provider.

2Check every disclosure

Each one hashes to a digest in the signed payload.

3Verify the Key Binding JWT

Holder key signature; nonce and audience match.

4Check revocation

Read the issuer's status list.

Every check passes

Yes

Use the disclosed attributes

No

Reject and offer another route

The verifier's checks on one SD-JWT VC presentation.[1][3]

Issuer signature. The ARF lists it first among the relying party's checks. Trust anchors come from Trusted Lists (ETSI TS 119 612) and Lists of Trusted Entities (ETSI TS 119 602).[3]

Disclosures. The signed payload holds an _sd array of digests; each disclosure is a salt, a claim name and a value, such as ["eluV5Og3gSNII8EYnsxA_A", "family_name", "Doe"].[1] Hash each one and find its digest. No match means the issuer did not sign it.

Key Binding JWT. When holder binding is required, the wallet "MUST return an SD-JWT with a Key Binding JWT". Its nonce must equal your request's nonce and its aud your Client Identifier, or over the Digital Credentials API your origin prefixed with origin:.[1] The specification's example:

{ "nonce": "n-0S6_WzA2Mj", "aud": "x509_san_dns:client.example.org", "iat": 1709838604, "sd_hash": "Dy-RYwZfaaoC3inJbLslgPvMp09bH-clYP_3qbRqtW4" }

Revocation. The relying party verifies the provider "did not revoke the PID or attestation".[3] Moldova's EVO Wallet, for one, documents an IETF Token Status List for this.[11]

Note

The PID portrait becomes mandatory only from 11 August 2028, so do not plan a face match against the wallet portrait before then.[5]

mdoc presentations via ISO/IEC 18013-7, in brief

For an mdoc, the VP Token holds a base64url-encoded DeviceResponse from ISO/IEC 18013-5 that "contains a signature or MAC over the SessionTranscript", including an OpenID4VP handover structure.[1] That handover binds the mdoc to your request, the way nonce and audience bind an SD-JWT VC.

Watch out

EU law applies "Annex C to ISO/IEC 18013-7:2025" for mdoc over the Digital Credentials API.[5] ISO lists the 2024 edition of 18013-7 as withdrawn and replaced, so check which edition your library implements.[8]

Our SD-JWT VC vs mdoc comparison covers when each format fits.

What the HAIP profile adds for EUDI verifiers

The High Assurance Interoperability Profile (HAIP) narrows OpenID4VP's options. The ARF already requires it for issuance, saying its use "is necessary to ensure interoperability".[3] For presentation, CIR 2026/1731 sets an "OpenID4VC-HAIP profile" and an "ISO/IEC-mdoc profile".[5]

RequirementFor your verifierSource
Access certificateSign with an x509_hash RP access certificate, ETSI TS 119 475CIR 2026/1731[5]
Registration certificateInclude it in verifier_infoCIR 2026/1731[5]
RegistrationRegister where you are establishedeIDAS Art. 5b(1)[4]
Wallet checksWallet units validate registration certificates only from 11 August 2028; not a registration deadlineCIR 2026/1731[5]

The registration certificate "describes the intended use of the relying party and indicates the attributes" it registered, and the registration regulation applies from 24 December 2026.[6] The 11 August 2028 date only covers the wallet-side check of that certificate, not registration.[5] Germany sums it up: an organisation "receives an access and registration certificate for the organization and the use case".[12] Our EUDI Wallet relying party guide covers registration in full.

Common mistakes when building an OpenID4VP verifier

MistakeFix
Reused or short noncesAt least 16 fresh random bytes per request[1]
No audience checkCompare aud with your Client Identifier or origin[1]
Asking for unregistered dataBuild the DCQL query from your registration[4]
Custom URI QR codes across devicesPrefer the Digital Credentials API[3]
Trusting trusted_authoritiesValidate the issuer against trust lists yourself[1]
Skipping revocationCheck the status every time[3]
Signing with the redirect_uri prefixIt cannot be signed; use x509_hash[1][5]

The wallet is also voluntary: access "shall not in any way be restricted or made disadvantageous" for people who do not use it, so your verifier sits next to another route.[4]

Testing resources

Start with reference software and conformance tests before you test against national wallets.

  • Run the conformance tests at conformance.eudi.dev.[3]
  • Read the reference implementation docs at docs.eudi.dev, which are documentation, not tests.[3]
  • Study the National Bank of Moldova's demo verifier and its source code.[13]
  • Check the Digital Credentials API draft before relying on the browser route.[9]

For the dates behind your test plan, see EUDI Wallet deadlines for 2026 and 2027.

How Didit helps with EUDI Wallet verification

EUDI Wallet acceptance is coming soon on Didit: it is on our roadmap, aligned with the EUDI Wallet timeline, in the same workflow you use today. Meanwhile, you can verify people remotely now.

You keep your relying-party duties. The eID integrations docs show how eIDs are turned on per country.

Didit provides

  • National eID sign-ins and the document route in one workflow
  • The evidence of every check

Stays with you

  • Your wallet-relying party registration
  • The onboarding decision and your policies

Plan your EUDI Wallet route with us

Tell us your countries and use case, and start with national eIDs and documents today.

Talk to usStart freeRead the docs

Key takeaways

  • OpenID4VP 1.0 is a final OpenID specification since 10 July 2025.
  • Send a DCQL query capped by your registration and a fresh nonce.
  • Verify the issuer signature, every disclosure, the Key Binding JWT and revocation.
  • EUDI verifiers sign with an x509_hash RP access certificate.
  • Private relying parties in scope accept the wallet by 24 December 2027.

Frequently asked questions

What is OpenID4VP?

OpenID for Verifiable Presentations is a protocol for requesting and presenting credentials. The wallet returns signed presentations in a VP Token, with no authorization code or access token to exchange. Version 1.0 became an OpenID Final Specification on 10 July 2025.[1][2]

Does the EUDI Wallet use OpenID4VP?

Yes, for remote presentation, next to ISO/IEC 18013-7. EU law sets an OpenID4VC-HAIP profile and an ISO/IEC-mdoc profile.[3][5]

What is DCQL?

The Digital Credentials Query Language is the JSON query naming the credentials and claims a verifier wants. The wallet returns presentations that match. For the EUDI Wallet, ask only for the attributes you registered.[1][4]

Which response mode should an EUDI verifier use?

A server-side verifier uses direct_post or the encrypted direct_post.jwt. Over the Digital Credentials API, the modes are dc_api and dc_api.jwt.[1]

How do I verify the Key Binding JWT?

Check its signature with the key bound in the credential, then check its nonce and audience against your request. Over the Digital Credentials API, the audience is your origin.[1]

Which client identifier prefix do EUDI verifiers use?

x509_hash, with an RP access certificate per ETSI TS 119 475. The registration certificate goes in verifier_info.[5]

Can I use a QR code across devices?

You can, but the ARF does not recommend custom URI schemes across devices because of phishing and relay attacks. It names the Digital Credentials API as the alternative.[3]

Can I face-match against the wallet portrait?

Not reliably yet. The portrait becomes mandatory PID data only from 11 August 2028.[5]

Where can I test an OpenID4VP verifier?

Run the conformance tests at conformance.eudi.dev and read the reference implementation docs at docs.eudi.dev. Moldova's central bank also published a demo verifier with source code.[3][13]

Sources

  1. OpenID for Verifiable Presentations 1.0, OpenID Foundation, Final Specification.
  2. OpenID for Verifiable Presentations 1.0 Final Specification Approved, OpenID Foundation, 10 July 2025.
  3. Architecture and Reference Framework v3.0.0, eu-digital-identity-wallet on GitHub, release of 23 July 2026.
  4. Regulation (EU) 2024/1183 (eIDAS 2), EUR-Lex, Official Journal of 30 April 2024.
  5. Commission Implementing Regulation (EU) 2026/1731, EUR-Lex, Official Journal of 22 July 2026.
  6. Commission Implementing Regulation (EU) 2025/848 on the registration of wallet-relying parties, EUR-Lex, Official Journal of 7 May 2025.
  7. Commission Implementing Regulation (EU) 2024/2977 on person identification data, EUR-Lex, Official Journal of 4 December 2024.
  8. ISO/IEC 18013-7, ISO standard page.
  9. Digital Credentials, W3C draft.
  10. Digital Credentials API shipped, Chrome for Developers.
  11. EVO Wallet developer guide, Government of Moldova, egov4dev.
  12. EUDI Wallet FAQ, eudi-wallet.gov.de.
  13. BNM demo verifier, Government of Moldova, egov4dev.

OpenID4VP is the part of the EUDI Wallet developers touch most, and it is stable enough to build against. See how Didit approaches wallet acceptance on the EUDI Wallet solution page, and the wider picture in our eIDAS 2 overview.

Verify people remotely while wallets roll out

Use national eIDs and the document route now, and talk to us about the EUDI Wallet.

Start freeTalk to us

Infrastructure for identity and fraud.

One API for KYC, KYB, Transaction Monitoring, and Wallet Screening. Integrate in 5 minutes.

Ask an AI to summarise this page