@openeudi/openid4vp 0.9.1 → 0.9.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -166,10 +166,15 @@ Wallets POST the Authorization Response to your `responseUri`. The library is st
166
166
 
167
167
  ### Unencrypted (`direct_post`)
168
168
 
169
- The envelope arrives as form-encoded JSON; parse it, check `state`, then verify:
169
+ The envelope arrives as form-encoded JSON; parse it, check `state`, then verify.
170
+
171
+ **mDOC SessionTranscript wall:** plain `direct_post` has no JWE, so there is no `apu` header and `verifyAuthorizationResponse` cannot auto-build the mDOC `SessionTranscript`. You must pass `options.mdocSessionTranscript` yourself. For wallets that use the OpenID4VP 1.0 Final unencrypted handover, omit `verifierEncryptionJwk` so the handover's `jwkThumbprint` is CBOR `null`:
170
172
 
171
173
  ```ts
172
- import { verifyAuthorizationResponse } from "@openeudi/openid4vp";
174
+ import {
175
+ buildOpenID4VPHandoverSessionTranscript,
176
+ verifyAuthorizationResponse,
177
+ } from "@openeudi/openid4vp";
173
178
 
174
179
  const envelope = parsedVpTokenObject; // { vp_token, state, ... }
175
180
 
@@ -177,12 +182,26 @@ if (envelope.state !== submittedState) {
177
182
  throw new Error("state mismatch — possible CSRF / replay");
178
183
  }
179
184
 
185
+ const mdocSessionTranscript = await buildOpenID4VPHandoverSessionTranscript({
186
+ clientId: verifierClientId,
187
+ nonce,
188
+ responseUri: verifierResponseUri,
189
+ // omit verifierEncryptionJwk → jwkThumbprint = null (unencrypted handover)
190
+ });
191
+
180
192
  const result = await verifyAuthorizationResponse(envelope, dcqlQuery, {
181
193
  trustedCertificates: [issuerCertDer],
182
194
  nonce,
195
+ clientId: verifierClientId,
196
+ responseUri: verifierResponseUri,
197
+ mdocSessionTranscript,
183
198
  });
184
199
  ```
185
200
 
201
+ Without a transcript, the mDOC parser fails closed (`claims: {}`, no `docType` on the failure result). DCQL matching against that doctype-less parse can then surface a misleading `doctype_mismatch` even when the wallet sent the correct credential — prefer `parsed.error` when diagnosing.
202
+
203
+ For `direct_post.jwt` auto-build (Annex B / `openid4vp-1.0`), see [mDOC SessionTranscript on the encrypted path](#mdoc-sessiontranscript-on-the-encrypted-path).
204
+
186
205
  ### Encrypted (`direct_post.jwt`)
187
206
 
188
207
  The wallet wraps the envelope in a JWE. Decrypt explicitly so you can check `state` against the decrypted envelope **before** verification runs:
@@ -214,7 +233,7 @@ const result = await verifyAuthorizationResponse(decrypted, dcqlQuery, {
214
233
 
215
234
  #### mDOC SessionTranscript on the encrypted path
216
235
 
217
- Verifying an mDOC credential requires the ISO 18013-5 `SessionTranscript` the device signed over (see [mDOC](#mdoc) below). For `direct_post.jwt`, `verifyAuthorizationResponse` can auto-build the `SessionTranscript` for you, in one of two profiles selected via `options.sessionTranscriptProfile`:
236
+ Verifying an mDOC credential requires the ISO 18013-5 `SessionTranscript` the device signed over (see [mDOC](#mdoc) below). For **unencrypted** `direct_post` (no JWE / no `apu`), auto-build does not run — pass `mdocSessionTranscript` explicitly as shown in [Unencrypted (`direct_post`)](#unencrypted-direct_post). For `direct_post.jwt`, `verifyAuthorizationResponse` can auto-build the `SessionTranscript` for you, in one of two profiles selected via `options.sessionTranscriptProfile`:
218
237
 
219
238
  - **`'iso-18013-7'` (default)** — the ISO 18013-7 Annex B OID4VP transcript, matching id2/id3-era wallets. Pass `options.clientId` and `options.responseUri` alongside the usual `options.nonce`, and the library derives the `mdoc-generated-nonce` from the JWE's `apu` header to construct the transcript before verification runs.
220
239
 
@@ -244,7 +263,7 @@ Verifying an mDOC credential requires the ISO 18013-5 `SessionTranscript` the de
244
263
 
245
264
  The transcript is `[null, null, ["OpenID4VPHandover", SHA-256(cbor([client_id, nonce, jwk_thumbprint | null, response_uri]))]]`, where `jwk_thumbprint` is the RFC 7638 SHA-256 thumbprint of `verifierEncryptionJwk` (or `null` when the response is unencrypted). Callers who need this transcript outside `verifyAuthorizationResponse` can use the exported `buildOpenID4VPHandoverSessionTranscript({ clientId, nonce, responseUri, verifierEncryptionJwk? })`.
246
265
 
247
- If you already have the transcript bytes (or are verifying an mDOC outside either auto-build path, e.g. the unencrypted `direct_post` flow), pass `options.mdocSessionTranscript: Uint8Array` explicitly — it always takes precedence over either auto-built value. `buildOid4vpSessionTranscript({ clientId, responseUri, nonce, mdocGeneratedNonce })` (Annex B) and `buildOpenID4VPHandoverSessionTranscript({ clientId, nonce, responseUri, verifierEncryptionJwk? })` (1.0-Final) are both exported for callers who need to construct a transcript themselves. Without a transcript, the mDOC parser fails closed — see [mDOC](#mdoc).
266
+ If you already have the transcript bytes (or are verifying an mDOC outside either auto-build path), pass `options.mdocSessionTranscript: Uint8Array` explicitly — it always takes precedence over either auto-built value. `buildOid4vpSessionTranscript({ clientId, responseUri, nonce, mdocGeneratedNonce })` (Annex B) and `buildOpenID4VPHandoverSessionTranscript({ clientId, nonce, responseUri, verifierEncryptionJwk? })` (1.0-Final) are both exported for callers who need to construct a transcript themselves. Without a transcript, the mDOC parser fails closed — see [mDOC](#mdoc). For the plain `direct_post` pattern, see [Unencrypted (`direct_post`)](#unencrypted-direct_post).
248
267
 
249
268
  ### Supported JWE algorithms
250
269
 
@@ -403,6 +422,14 @@ Verifier-side conformance is automated against a self-hosted OpenID Foundation c
403
422
  - **[@openeudi/dcql](https://www.npmjs.com/package/@openeudi/dcql)** -- DCQL query matching engine used internally by `verifyPresentation`.
404
423
  - **[eIDAS Pro](https://eidas-pro.eu)** -- Managed verification service with admin dashboard, webhook integrations, and plugin support for WooCommerce and Shopify.
405
424
 
425
+ ## Community integrations
426
+
427
+ Third-party projects built on this library. These are **not** maintained or audited by OpenEUDI -- evaluate them on their own merits.
428
+
429
+ - **[eudi-verify](https://github.com/eudi-verify/eudi-verify)** -- Relying-party widget and API, running `@openeudi/openid4vp` as one of two pluggable verifier engines. Includes public [interop notes](https://github.com/eudi-verify/eudi-verify/blob/main/docs/INTEROP.md) covering `mso_mdoc` age-over-18 against an EU Age Verification reference wallet. Demo: [demo.eudi-verify.eu](https://demo.eudi-verify.eu/).
430
+
431
+ Built something on `@openeudi/openid4vp`? Open an issue and we're happy to consider listing it here.
432
+
406
433
  ## Migration
407
434
 
408
435
  See [CHANGELOG.md](./CHANGELOG.md) for per-release changes. Key migration moments: