Core Concepts Overview
You're building this ecosystem together with us, the ecosystem orchestrator. Getting started from scratch can feel overwhelming, so this guide gives you a research path: the sources you need to build your knowledge, and a foundation to design your own use case on.
Before you start: OpenID4VP fundamentals
OpenID4VP sits at the intersection of several mature but independently deep domains. An architect who wants to own the full stack — not just wire up a library — needs fluency across all of them. The list below maps each domain to the specific role it plays in an OpenID4VP implementation. Work through any gaps before diving into the protocol specification; trying to read the spec without this foundation will leave you guessing at every other sentence.
Verifiable Credentials and Verifiable Presentations
The payload the wallet returns is a Verifiable Presentation wrapping one or more Verifiable Credentials. You need to understand the VC data model — issuer, subject, claims, proof — and the relationship between credential and presentation. This is the domain model your response-parsing logic operates on, and it informs which fields you extract and trust.
Key topics: VC data model, credential vs. presentation distinction, issuer key binding, holder binding, selective disclosure.
Public Key Infrastructure (PKI) and X.509 Certificates
OpenID4VP in the EUDI context requires your Relying Party backend to present an Access Certificate. You must
understand certificate chains, how a verifier walks the chain to a trust anchor, certificate fields relevant to
identity (CN, SAN, OID extensions), and revocation mechanisms (CRL, OCSP). You will also need to embed and serve
these certificates correctly inside the signed request object.
Key topics: X.509 v3 structure, certificate chains, CA hierarchy, PEM vs. DER encoding.
IETF RFC 5280 — X.509 PKI Certificate Profile
Level of Assurance (LoA)
Level of Assurance defines how much confidence a system can have in a claimed identity. In eIDAS 2.0 and the EUDI Wallet context, three levels are defined: Low, Substantial, and High. The level you must request is a legal and risk-driven decision — but it has direct, concrete consequences for your software architecture.
From an architectural perspective, LoA shapes the following decisions:
- Which credential format and profile you must accept. LoA High mandates stricter cryptographic requirements (e.g. the OpenID4VC High Assurance Interoperability Profile), narrowing the set of acceptable algorithms and binding mechanisms your verification logic must enforce.
- Certificate and trust chain requirements. Higher assurance levels require your Access Certificate to be issued by a qualified trust service provider, which affects procurement, renewal cycles, and your certificate management component.
- Key binding and holder authentication. At LoA High, the wallet must cryptographically prove that the credential was presented by the legitimate holder (device binding / key binding). Your response validation must verify this proof, not just the credential signature.
- Audit and non-repudiation. Higher assurance levels often imply stricter logging requirements — what you must record, how long, and in what tamper-evident form — which affects your persistence layer and operational setup.
Understanding which LoA your use case requires before you design the system avoids costly late-stage rework.
For a plain-language explanation of what the three levels mean and how to choose one for your use case, see What is Level of Assurance (LoA)?.
RESTful HTTP APIs
Both your request endpoint and response endpoint are plain HTTP resources. You need a solid grip on HTTP semantics: methods, status codes, content negotiation, caching headers, and CORS policy — because the wallet is a native mobile app making cross-origin requests to your backend. Misconfigured CORS or wrong status codes are among the most common causes of silent failures in integration testing.
Key topics: HTTP methods and status codes, Content-Type, CORS headers (Access-Control-Allow-Origin, preflight),
redirect chains (302), query-string encoding.
Session and State Management
OpenID4VP is a redirect-based flow that spans multiple HTTP round-trips: the user lands on your frontend, a link opens
the wallet, the wallet calls your backend asynchronously, and your frontend polls for completion. You must design a
session model that correlates the nonce and state parameters across these hops, survives the user switching between
browser and native app, and is resistant to fixation and replay attacks. This is the HTTP-layer session that correlates
a user's browser/app interactions — distinct from the cryptographic binding of the presentation itself to a specific
holder and exchange. This will be covered in the upcoming guide 'Types of Binding'.
Key topics: server-side session stores vs. signed cookies, correlation by nonce/state, session lifecycle (creation, expiry, invalidation), polling vs. push notification patterns, CSRF protection.
OWASP — Session Management Cheat Sheet
Credential Formats (SD-JWT-VC and mdoc)
Credentials in the EUDI ecosystem are encoded in one of two formats: SD-JWT-VC (a JWT-based format with selective disclosure) or mdoc (ISO/IEC 18013-5, a CBOR-based format). Your parsing and verification logic must handle whichever format the wallet presents. The two formats have fundamentally different encodings, trust validation paths, and library ecosystems — choosing the right one for your use case, or supporting both, is an early architectural decision.
For a detailed comparison and guidance on which format applies to your scenario, see the dedicated format reference.
JSON Object Signing and Encryption (JOSE)
SD-JWT-VC is built entirely on the JOSE family of standards. You must be comfortable with all three layers before you can read, verify, or produce any SD-JWT-VC artefact:
-
JWT / JWS (RFC 7519 / RFC 7515) — Almost every artefact in the flow is a JWT: the signed request object your backend serves to the wallet, the
id_tokenvariant of a response, and the credential claims themselves. Understand the three-partheader.payload.signaturestructure, the standard claim set (iss,aud,exp,iat,nonce), how the signing algorithm is negotiated viaalg, and what end-to-end signature verification actually involves. -
JWE (RFC 7516) — The wallet encrypts its Verifiable Presentation response using the Relying Party's public key before posting it to the response endpoint. Understand how JWE differs from JWS (confidentiality vs. integrity), key-wrapping algorithms (
ECDH-ES+A256KW), content encryption algorithms (A256GCM), and the fact that an ephemeral encryption key pair must be generated fresh per session. -
JWK / JWKS (RFC 7517) — Key material is exchanged as JSON Web Key Sets. The wallet fetches your JWKS to encrypt its response; you fetch the issuer's JWKS to verify credential signatures. Know key types (
EC,RSA), usage fields (use,key_ops), key IDs (kid), and how to rotate keys without breaking in-flight sessions.
IETF RFC 7519 — JWT · RFC 7515 — JWS · RFC 7516 — JWE · RFC 7517 — JWK
mdoc, CBOR and ISO/IEC 18013-5
The mdoc format uses an entirely different encoding stack from SD-JWT-VC. Instead of JSON and JWTs, it is based on CBOR (Concise Binary Object Representation) for encoding and COSE (CBOR Object Signing and Encryption) for signatures and encryption. The credential structure, namespace model, and trust validation path are defined in ISO/IEC 18013-5, the international standard for mobile driving licences — which EUDI adopts as the vehicle for mDL and other mdoc-typed credentials.
Key topics: CBOR encoding (RFC 8949), COSE signing and encryption (RFC 9052), mdoc namespace and element structure,
DeviceResponse and DeviceSigned objects, mdoc-specific trust chain validation.
RFC 8949 — CBOR · RFC 9052 — COSE · ISO/IEC 18013-5 (paid standard)
Digital Credential Query Language (DCQL)
OpenID4VP uses DCQL to express which credential attributes the Relying Party requests from the wallet. You must understand how to model a query (credential type, claim paths, optional vs. required), how alternative credential formats are expressed as alternatives within one query, and how the wallet matches a query against its stored credentials. Your DCQL implementation is the direct translation of your business requirements into protocol-level attribute requests.
Key topics: DCQL query structure, credential_sets, claim paths, format identifiers (vc+sd-jwt, mso_mdoc), optional
claims.
Trust Frameworks, Trusted Lists, and Governance (LoTL / TSL)
Verifying that a presented credential was issued by a legitimate issuer requires checking against a Trusted List — in the EUDI context, the List of Trusted Lists (LoTL) and national Trust Service Lists (TSL). You need to understand how trust anchors are published, how to fetch and cache them, and how to walk the certificate chain from the credential's issuer key all the way to a trusted root. This is non-trivial operational work, not just a library call.
Trust anchors are not static: they exist within a governance model you need to design around, not just a data feed you consume. The European Commission operates the LoTL itself, but each Member State's national supervisory body governs its own TSL — deciding which Trust Service Providers are accredited, suspended, or withdrawn. An entry's status can change (a TSP loses accreditation, a root key is rotated or revoked) independently of any action on your side, so your architecture must treat trust anchors as a live, revocable data set: define a re-fetch/cache-invalidation policy, decide how to behave when the LoTL endpoint is unreachable (fail closed vs. serve a stale cache with a bounded TTL), and log which trust anchor version was active at the time of each verification for auditability.
Key topics: ETSI TS 119 612 (TSL format), LoTL structure, trust anchor discovery and governance, TSP accreditation/withdrawal lifecycle, certificate chain validation, CRL fetching and caching, cache invalidation strategy.
European Commission Trust List Browser · ETSI TS 119 612
Deep Linking and App-to-App Invocation
The wallet is a native mobile application. Your Relying Party frontend must construct a correctly formed openid4vp://
URI (or a universal/app link variant) that opens the wallet, passes the request URI, and survives the platform-specific
redirect back to your frontend after the presentation is complete. The mechanics differ between iOS (Universal Links)
and Android (App Links / Intent Filters), and a broken link scheme will silently fail on one platform.
Key topics: custom URI schemes, iOS Universal Links, Android App Links, openid4vp:// scheme, response URI callback,
same-device vs. cross-device flow.
OpenID4VP — Invocation section · Apple — Universal Links · Android — App Links
Key Management and Secrets Hygiene
Every cryptographic operation in the stack depends on the secure lifecycle of private keys: generation, storage, rotation, and destruction. A mismanaged key undermines every other security measure. You must choose an appropriate secret store (HSM, cloud KMS, or software keystore) that matches your threat model, and you must ensure that ephemeral per-session keys (used for JWE response encryption) are isolated from long-lived signing keys.
Key topics: symmetric vs. asymmetric key storage, HSM vs. software keystore trade-offs, key rotation without downtime, ephemeral key isolation, secret scanning in CI.
OWASP — Key Management Cheat Sheet
OpenID4VP — The core of credential presentation
The domains above are the ground the protocol stands on. This section explains the protocol itself.
OpenID4VP — OpenID for Verifiable Presentations — answers a single question: how does an application ask a wallet for verified data about its user, and receive an answer it can trust? It is the protocol every Relying Party in the German EUDI Wallet ecosystem implements, and it is the only protocol that runs between your Relying Party backend and the wallet.
Who takes part
Three parties are active in an OpenID4VP exchange:
- The Relying Party — your application, acting as verifier. It asks for attributes and validates what comes back.
- The Wallet — the user's app. It holds the credentials, shows the request to the user, and builds the response.
- The User — decides whether to share, and what to share.
The Issuer is not part of the exchange. It signed the credential at some earlier point in time. You verify that signature against a trust anchor, so you never have to contact the issuer during a presentation.
How an exchange runs
- You build a request. It states who you are (
client_id), which attributes you need (a DCQL query), and a fresh random value that ties the answer to this one exchange (nonce). You publish the request as a signed document and keep the matching session in your backend. - You hand the request to the wallet. The user either scans a QR code (the wallet runs on a second device) or taps
a link that opens the wallet on the same device. Either way the wallet only receives a URL (
request_uri) pointing at your signed request — the request itself stays on your server. - The wallet checks who is asking. It fetches the request, verifies your signature, and validates your Access Certificate against the trusted lists. A verifier that cannot prove its identity never reaches the user.
- The user decides. The wallet shows which attributes you asked for and who is asking. The user confirms or cancels. Thanks to selective disclosure, the wallet reveals only the requested attributes — asking for a date of birth does not expose an address.
- The wallet sends the response. It posts a Verifiable Presentation to your
response_uri, encrypted with your public key. The presentation contains the disclosed attributes, the issuer's signature over the credential, and a proof of possession from the user's device key covering yournonce. - You validate and continue. You decrypt the response, check the issuer signature against a trust anchor, check the
holder's proof of possession, confirm the
noncematches the session you started, and only then release the result to your business logic.
What this design buys you
- You learn nothing you did not ask for. The DCQL query is the full extent of what you receive.
- The user is never silently profiled. Every presentation requires a visible, explicit confirmation in the wallet.
- Trust is verifiable offline. Signatures and trusted lists carry the trust; no live call to the issuer is needed.
- Both parties authenticate. The wallet proves the credential belongs to its holder, and your Access Certificate proves to the wallet that you are an authorised verifier.
Where the work sits for you
The protocol assigns you four concrete responsibilities. Everything else in this guide serves one of them:
| Responsibility | What you build |
|---|---|
| Express what you need | A DCQL query derived from your actual business requirement — nothing more |
| Prove who you are | Access Certificate handling and a signed request object served from your request_uri |
| Receive the answer | A response_uri endpoint that decrypts and parses the presentation |
| Decide whether to trust it | Signature, trust chain, holder binding, and nonce validation before any business decision |
Key topics: authorisation request and signed request object, request_uri and response_uri, client_id schemes,
nonce, encrypted responses, same-device vs. cross-device flow.
OpenID4VP 1.0 · OpenID4VC High Assurance Interoperability Profile
Further Reading
| Documentation | Read this, when ... |
|---|---|
| OpenID4VP | ... you want to deeply understand the technical protocol between verifier and wallet app |
| OpenID4VC High Assurance Interoperability Profile | ... you need to authenticate on level of assurance high |
| ARF | ... you want to understand the big picture of the whole european ecosystem |
| Blueprint for the EUDI Wallet Ecosystem in Germany | ... you want to understand the german approach to this architecture |
| wallet-development-documentation | ... you want to understand the issuance of the pid in depth |