Skip to content

DC API Verifier Playground (France Identite)

A developer‑oriented playground to test Digital Credentials API flows with:

  • OpenID4VP (unsigned) over dc_api.jwt
  • ISO 18013‑7 (DeviceRequest over DC API) for mdoc

It focuses on ISO/IEC 18013‑5 mdoc parsing and extraction for wallet interoperability testing. This is a demo (not production‑ready).

Verifier Open Verifier
Source code GitHub

Browser Support

  • Chrome / Chromium: OpenID4VP (dc_api.jwt) and ISO 18013‑7 (org-iso-mdoc).
  • Safari: ISO 18013‑7 only. OpenID4VP over DC API is not supported.

Quick Overview

Supported Protocols 1. OpenID4VP (unsigned) over DC API (response_mode=dc_api.jwt) 2. ISO 18013‑7 DeviceRequest over DC API (protocol=org-iso-mdoc)

Supported Credentials (mdoc) 1. PID eu.europa.ec.eudi.pid.1 2. Age Verification eu.europa.ec.av.1


What This Verifier Does

OpenID4VP (Unsigned) via DC API - Builds DCQL requests - Invokes the wallet in a compatible browser - Accepts JWE/JWS dc_api.jwt responses

ISO 18013‑7 (DeviceRequest over DC API) - Builds ISO 18013‑5 DeviceRequest (CBOR, base64url) - Encrypts/Decrypts using the Annex C DC API profile

Verification & Display - Parses mdoc DeviceResponse - Verifies IssuerAuth signatures - Verifies valueDigests when present - Displays extracted attributes and issuer certificate

Developer Tools - Request JSON editor - CBOR debug section - UI console with backend logs - Annex C / HPKE debug traces


Architecture

Browser (UI)
  -> Node.js Express Backend
  -> Wallet (DC API / OpenID4VP)

Backend - CBOR parsing - ISO 18013‑5 mdoc parsing - IssuerAuth + valueDigest verification - DeviceAuth parsing (full verification requires SessionTranscript)

Frontend - Static HTML / CSS / JS - Step‑based flow UI - DCQL request builder


Protocols Explained

Digital Credentials API (DC API)

DC API is the browser‑facing transport to invoke a wallet and exchange request/response payloads. It does not define the credential format — it only transports it.

In this playground, DC API transports:

  • OpenID4VP (unsigned) via dc_api.jwt
  • ISO 18013‑7 via protocol=org-iso-mdoc

ISO/IEC 18013‑5 (mdoc)

ISO 18013‑5 defines the mdoc data model and cryptographic structures:

  • DeviceResponse → contains documents
  • Each DocumentdocType, issuerSigned, optionally deviceSigned
  • issuerSigned contains:
  • issuerAuth (COSE_Sign1 over the MSO)
  • nameSpaces (arrays of IssuerSignedItemBytes)
  • valueDigests allow per‑item integrity verification

This verifier extracts attributes from IssuerSignedItemBytes and verifies issuer signatures/digests when available.

ISO 18013‑7 (DeviceRequest over DC API)

ISO 18013‑7 defines how an mdoc DeviceRequest is sent via DC API and how the encrypted response is returned.

Annex C DC API profile (simplified):

  • Request:
  • deviceRequest (CBOR, base64url)
  • encryptionInfo (CBOR, base64url)
  • Response:
  • EncryptedResponse = ["dcapi", { enc: bstr, cipherText: bstr }]

Encryption uses HPKE single‑shot (RFC 9180):

  • KEM: DHKEM(P‑256)
  • KDF: HKDF‑SHA256
  • AEAD: AES‑128‑GCM

The HPKE info is the CBOR‑encoded SessionTranscript (see below). aad is empty.

OpenID4VP (Unsigned) over DC API

OpenID4VP is an OAuth‑style protocol to request credentials. In this playground:

  • Requests are unsigned (dev mode)
  • DCQL describes requested claims
  • Wallet returns a dc_api.jwt response (JWE/JWS)
  • For mdoc, the vp_token contains a base64url CBOR DeviceResponse or Document

SessionTranscript (Annex C)

The SessionTranscript binds the request and origin to the cryptographic session:

SessionTranscript = [
  null,
  null,
  ["dcapi", dcapiInfoHash]
]

dcapiInfo = [Base64EncryptionInfo, SerializedOrigin]

dcapiInfoHash = SHA-256(CBOR(dcapiInfo))
  • Base64EncryptionInfo = base64url CBOR of encryptionInfo
  • SerializedOrigin = ASCII serialization of the origin

This CBOR structure is used as HPKE info for ISO 18013‑7 encryption/decryption.


OpenID4VP vs ISO 18013‑7 (At a Glance)

Aspect OpenID4VP ISO 18013‑7
Request OAuth/DCQL DeviceRequest (CBOR) + encryptionInfo
Response dc_api.jwt (JWE/JWS) EncryptedResponse with HPKE ciphertext
Crypto JWT container HPKE single‑shot + AES‑128‑GCM
Parsing JWT -> vp_token -> CBOR HPKE decrypt -> DeviceResponse

Getting Started (Local)

npm install
node server.js

Open:

http://localhost:3000

Some DC API implementations require a secure context (https). Use a local HTTPS proxy if needed.


Using the App

  1. Build request: choose protocol, credential type, attributes
  2. Send request: invoke the wallet via DC API
  3. Receive response: paste the wallet JSON response
  4. Verify: issuer signature and value digest checks
  5. Display: extracted attributes and portrait

ISO 18013‑5 Notes

Value Digests

MSO.valueDigests[namespace][digestID]

Digest computed over:

IssuerSignedItemBytes = Tag(24, embedded CBOR)

DeviceAuth Full DeviceAuth verification requires the correct SessionTranscript. The demo parses DeviceAuth but does not fully verify it without transcript bytes.


Debugging (ISO 18013‑7 / Annex C)

The UI console mirrors backend logs. With debug enabled, the server emits Annex C tracing:

  • enc (ephemeral public key) hex
  • cipherText hex
  • dcapiInfo CBOR hex
  • dcapiInfoHash hex
  • SessionTranscript CBOR hex
  • aad hex (empty)
  • HPKE intermediate secrets (when available): sharedSecret, aeadKey, baseNonce

Enable debug logs:

DEBUG=1 node server.js
DEBUG=1 DEBUG_ANNEXC=1 node server.js
DEBUG=1 DEBUG_ANNEXC=1 DEBUG_ANNEXC_SECRETS=1 node server.js

Known Limitations

  • Not production‑hardened
  • DeviceAuth full verification requires SessionTranscript
  • No certificate trust chain validation
  • HTTPS not enforced by default