@bedrock/vc-delivery 7.16.0 → 7.16.1

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
@@ -1 +1,573 @@
1
- # bedrock-vc-delivery
1
+ # @bedrock/vc-delivery
2
+
3
+ A [Bedrock][] module that provides a **Verifiable Credential (VC) Workflow
4
+ Service** for issuing and exchanging VCs using multiple protocols. It enables
5
+ configurable, multi-step credential exchange workflows with support for the
6
+ VC-API, OpenID for Verifiable Credential Issuance (OID4VCI), OpenID for
7
+ Verifiable Presentations (OID4VP), and an Invite Request protocol.
8
+
9
+ ## Table of Contents
10
+
11
+ - [Background](#background)
12
+ - [Features](#features)
13
+ - [Requirements](#requirements)
14
+ - [Installation](#installation)
15
+ - [Quick Start](#quick-start)
16
+ - [Configuration](#configuration)
17
+ - [Workflow Config](#workflow-config)
18
+ - [Credential Templates](#credential-templates)
19
+ - [Steps](#steps)
20
+ - [Issuer Instances](#issuer-instances)
21
+ - [OID4VCI Options](#oid4vci-options)
22
+ - [OID4VP Client Profiles](#oid4vp-client-profiles)
23
+ - [HTTP API](#http-api)
24
+ - [Exchanges](#exchanges)
25
+ - [Protocols](#protocols)
26
+ - [OID4VCI Endpoints](#oid4vci-endpoints)
27
+ - [OID4VP Endpoints](#oid4vp-endpoints)
28
+ - [Invite Request Endpoints](#invite-request-endpoints)
29
+ - [Protocols](#supported-protocols)
30
+ - [VC-API](#vc-api)
31
+ - [OID4VCI](#oid4vci)
32
+ - [OID4VP](#oid4vp)
33
+ - [Invite Request](#invite-request)
34
+ - [Exchange Lifecycle](#exchange-lifecycle)
35
+ - [Multi-Step Workflows](#multi-step-workflows)
36
+ - [Security](#security)
37
+ - [Backwards Compatibility](#backwards-compatibility)
38
+ - [License](#license)
39
+
40
+ ## Background
41
+
42
+ This module implements the server-side infrastructure for **Verifiable Credential
43
+ delivery**. A *workflow* is a reusable configuration that defines how credentials
44
+ are issued and/or verified. An *exchange* is a single instance of that workflow —
45
+ a live, stateful session between a workflow service and an exchange client (e.g.
46
+ a digital wallet).
47
+
48
+ Workflows are registered with an associated set of authorization capabilities
49
+ (zcaps) that grant the service permission to issue and verify credentials on
50
+ behalf of the workflow owner.
51
+
52
+ ## Features
53
+
54
+ - **Multi-protocol support**: VC-API, OID4VCI v1.0, OID4VP 1.0, and Invite
55
+ Request (with backwards compatibility for OID4VCI Draft 13 and OID4VP Draft
56
+ 18).
57
+ - **Multi-step exchanges**: Define sequential steps that mix presentation
58
+ verification and credential issuance within a single exchange.
59
+ - **JSONata credential templates**: Dynamically generate credential content
60
+ from exchange variables using [JSONata][] expressions.
61
+ - **Multiple issuer instances**: Configure up to 10 independent issuer
62
+ instances per workflow, each with its own zcap and supported credential
63
+ formats.
64
+ - **OID4VP client profiles**: Configure up to 10 OID4VP client profiles per
65
+ workflow, including support for signed authorization requests and mDL/ISO
66
+ 18013-7 presentation flows.
67
+ - **OAuth2 / zcap authorization**: Workflow management endpoints support both
68
+ zcap-based and OAuth2-based authorization.
69
+ - **Configurable exchange TTL**: Exchanges expire automatically (default 15
70
+ minutes, maximum 48 hours).
71
+
72
+ ## Requirements
73
+
74
+ - Node.js >= 20
75
+ - MongoDB (via [`@bedrock/mongodb`][])
76
+ - A running [Bedrock][] application with the required peer dependencies (see
77
+ `peerDependencies` in `package.json`)
78
+
79
+
80
+
81
+ ## Installation
82
+
83
+ ```sh
84
+ npm install @bedrock/vc-delivery
85
+ ```
86
+
87
+ Then import the module in your Bedrock application entry point:
88
+
89
+ ```js
90
+ import '@bedrock/vc-delivery';
91
+ ```
92
+
93
+ The module self-registers with Bedrock on import and will set up all routes
94
+ and storage on startup.
95
+
96
+ ## Quick Start
97
+
98
+ ### 1. Create a workflow configuration
99
+
100
+ ```js
101
+ // POST /workflows
102
+ {
103
+ "sequence": 0,
104
+ "controller": "did:key:z6Mk...",
105
+ "credentialTemplates": [{
106
+ "type": "jsonata",
107
+ "template": "{ '@context': ['https://www.w3.org/2018/credentials/v1'], 'type': ['VerifiableCredential'], 'credentialSubject': {'id': subject} }"
108
+ }],
109
+ "initialStep": "issue",
110
+ "steps": {
111
+ "issue": {
112
+ // you can use static step parameters like this, but also see
113
+ // `stepTemplate` below for more powerful dynamic steps instead!
114
+ "issueRequests": [{ "credentialTemplateIndex": 0 }]
115
+ }
116
+ },
117
+ "zcaps": {
118
+ "issue": { /* delegated issue zcap */ }
119
+ }
120
+ }
121
+ ```
122
+
123
+ ### 2. Create an exchange
124
+
125
+ ```js
126
+ // POST /workflows/:workflowId/exchanges
127
+ {
128
+ "ttl": 900,
129
+ "variables": {
130
+ "subject": "did:example:holder123"
131
+ }
132
+ }
133
+ // Response: 204 No Content; Location header contains exchange URL
134
+ ```
135
+
136
+ ### 3. Execute the exchange (VC-API)
137
+
138
+ ```js
139
+ // POST /workflows/:workflowId/exchanges/:exchangeId
140
+ {}
141
+ // Response:
142
+ {
143
+ "verifiablePresentation": { /* VP containing issued VCs */ }
144
+ }
145
+ ```
146
+
147
+ ## Configuration
148
+
149
+ ### Workflow Config
150
+
151
+ Workflows are created and managed via the [`@bedrock/service-core`][] HTTP
152
+ API at `/workflows`. The configuration body accepts the following custom
153
+ properties in addition to standard service-core fields:
154
+
155
+ | Property | Type | Required | Description |
156
+ |----------|------|----------|-------------|
157
+ | `credentialTemplates` | Array | No | List of JSONata credential templates to issue |
158
+ | `steps` | Object | No | Named step definitions for multi-step exchanges |
159
+ | `initialStep` | String | Required if `steps` present | Name of the first step to execute |
160
+ | `issuerInstances` | Array | No | Up to 10 issuer instance configurations |
161
+ | `zcaps` | Object | No | Authorization capability references |
162
+
163
+ If `credentialTemplates` are provided, either a top-level `zcaps.issue`
164
+ or at least one `issuerInstances` entry with its own issue zcap is required.
165
+
166
+ ### Credential Templates
167
+
168
+ Credential templates use [JSONata][] to dynamically produce credential JSON.
169
+ Exchange `variables` and built-in `globals` are available as template
170
+ bindings.
171
+
172
+ ```js
173
+ "credentialTemplates": [{
174
+ "type": "jsonata",
175
+ "id": "myTemplate", // optional, for referencing in issueRequests
176
+ "template": "{ ... }" // JSONata expression returning a VC object
177
+ }]
178
+ ```
179
+
180
+ **Built-in template globals:**
181
+
182
+ | Variable | Description |
183
+ |----------|-------------|
184
+ | `globals.exchange.id` | The local exchange ID |
185
+ | `globals.exchangeId` | The full exchange URL |
186
+ | `globals.workflow.id` | The workflow ID |
187
+
188
+ ### Steps
189
+
190
+ Steps define the interactive logic of an exchange. Each step can request a
191
+ Verifiable Presentation, issue credentials, or both.
192
+
193
+ ```js
194
+ "steps": {
195
+ "verify": {
196
+ "verifiablePresentationRequest": { /* VPR object */ },
197
+ "nextStep": "issue"
198
+ },
199
+ "issue": {
200
+ "issueRequests": [
201
+ { "credentialTemplateIndex": 0 }
202
+ ]
203
+ }
204
+ },
205
+ "initialStep": "verify"
206
+ ```
207
+
208
+ **Step fields:**
209
+
210
+ | Field | Description |
211
+ |-------|-------------|
212
+ | `issueRequests` | Array of credential issue request parameters |
213
+ | `verifiablePresentationRequest` | VPR to send to the client |
214
+ | `verifiablePresentation` | VP to return immediately without client input |
215
+ | `createChallenge` | `true` to generate and attach a challenge nonce to the VPR |
216
+ | `nextStep` | Name of the step to transition to after this one completes |
217
+ | `openId` | OID4VP options for this step |
218
+ | `jwtDidProofRequest` | Request a DID-bound JWT proof |
219
+ | `divpDidProofRequest` | Request a DI-VP DID proof |
220
+ | `callback.url` | URL to call when exchange state updates |
221
+ | `presentationSchema` | JSON Schema to validate received presentations |
222
+ | `verifyPresentationOptions` | Additional options for presentation verification |
223
+ | `verifyPresentationResultSchema` | JSON Schema to validate verification results |
224
+ | `allowUnprotectedPresentation` | Allow presentations without a proof |
225
+ | `redirectUrl` | URL to redirect the exchange client upon completion |
226
+
227
+ Steps may also be defined as **templated steps**, where a JSONata
228
+ `stepTemplate` expression dynamically generates the step configuration from
229
+ exchange variables at runtime:
230
+
231
+ ```js
232
+ "steps": {
233
+ "issue": {
234
+ "stepTemplate": {
235
+ "type": "jsonata",
236
+ "template": "{ 'issueRequests': [{ 'credentialTemplateIndex': 0 }] }"
237
+ }
238
+ }
239
+ }
240
+ ```
241
+
242
+ ### Issuer Instances
243
+
244
+ `issuerInstances` allows a workflow to configure multiple issuers, each with
245
+ different capabilities and supported credential media types. Up to 10 instances
246
+ are supported.
247
+
248
+ ```js
249
+ "issuerInstances": [{
250
+ "id": "myIssuer", // optional identifier
251
+ "supportedMediaTypes": ["application/vc"],
252
+ "zcapReferenceIds": {
253
+ "issue": "myIssuerZcap"
254
+ },
255
+ "oid4vci": {
256
+ "supportedCredentialConfigurations": { // optional explicit OID4VCI config
257
+ "MyCredential_ldp_vc": { /* credential configuration */ }
258
+ }
259
+ }
260
+ }]
261
+ ```
262
+
263
+ Each issuer instance references a zcap in the workflow's `zcaps` map by its
264
+ `zcapReferenceIds.issue` key.
265
+
266
+ ### OID4VCI Options
267
+
268
+ When creating an exchange with OID4VCI support, pass an `openId` object in the
269
+ exchange creation body:
270
+
271
+ ```js
272
+ // POST /workflows/:workflowId/exchanges
273
+ {
274
+ "openId": {
275
+ "preAuthorizedCode": "abc123",
276
+ "oauth2": {
277
+ "generateKeyPair": { "algorithm": "ES256" }
278
+ // or provide an existing key pair:
279
+ // "keyPair": { "privateKeyJwk": {...}, "publicKeyJwk": {...} }
280
+ }
281
+ }
282
+ }
283
+ ```
284
+
285
+ > **Deprecated:** `expectedCredentialRequests` is deprecated and should not be
286
+ > used in new workflows. Credential configurations are inferred from
287
+ > `issuerInstances` instead.
288
+
289
+ ### OID4VP Client Profiles
290
+
291
+ OID4VP client profiles allow fine-grained control over how authorization
292
+ requests are constructed and which wallet/verifier protocols are used. Up to 10
293
+ profiles are supported per workflow step.
294
+
295
+ ```js
296
+ // in a step:
297
+ "openId": {
298
+ "clientProfiles": {
299
+ "myProfile": {
300
+ "createAuthorizationRequest": "/authzReqVar",
301
+ "client_id": "https://verifier.example",
302
+ "client_id_scheme": "redirect_uri",
303
+ "response_mode": "direct_post",
304
+ "response_uri": "https://verifier.example/callback",
305
+ "protocolUrlParameters": {
306
+ "name": "OID4VP",
307
+ "scheme": "openid4vp",
308
+ "version": "OID4VP-1.0" // or "OID4VP-draft18"
309
+ }
310
+ }
311
+ }
312
+ }
313
+ ```
314
+
315
+ > **Deprecated:** `presentation_definition` (Presentation Exchange) is a
316
+ > pre-OID4VP 1.0 mechanism and is deprecated. Prefer `dcql_query` for new
317
+ > implementations.
318
+
319
+ Supported `response_mode` values include `direct_post`, `direct_post.jwt`,
320
+ `dc_api`, and `dc_api.jwt`.
321
+
322
+ ## HTTP API
323
+
324
+ All endpoints support CORS. Authorization uses zcaps or OAuth2 — not cookies
325
+ — so CSRF is not a concern.
326
+
327
+ ### Exchanges
328
+
329
+ #### Create Exchange
330
+
331
+ ```
332
+ POST /workflows/:workflowId/exchanges
333
+ ```
334
+
335
+ **Body** (`application/json`):
336
+
337
+ | Field | Type | Description |
338
+ |-------|------|-------------|
339
+ | `ttl` | Number | Seconds until expiry (default: 900, max: 172800) |
340
+ | `expires` | String | ISO 8601 expiry date (alternative to `ttl`) |
341
+ | `variables` | Object | Key/value pairs available in credential templates and step templates |
342
+ | `openId` | Object | OID4VCI configuration (see [OID4VCI Options](#oid4vci-options)) |
343
+
344
+ > **Note:** The schema uses `additionalProperties: false`; fields not listed above (including `step`) will be rejected by the validator.
345
+
346
+ **Response**: `204 No Content` with a `Location` header pointing to the exchange URL.
347
+
348
+ #### Get Exchange
349
+
350
+ ```
351
+ GET /workflows/:workflowId/exchanges/:exchangeId
352
+ ```
353
+
354
+ Returns the current exchange state. Private keys and secrets are never
355
+ included in the response.
356
+
357
+ #### Use Exchange (VC-API)
358
+
359
+ ```
360
+ POST /workflows/:workflowId/exchanges/:exchangeId
361
+ ```
362
+
363
+ **Body** (`application/json`):
364
+
365
+ | Field | Type | Description |
366
+ |-------|------|-------------|
367
+ | `verifiablePresentation` | Object | VP to submit (if requested by the current step) |
368
+
369
+ **Response**: A JSON object, which may contain:
370
+ - `verifiablePresentation` — a VP with issued credentials
371
+ - `verifiablePresentationRequest` — a VPR requiring the client to submit a VP
372
+
373
+ ### Protocols
374
+
375
+ #### Get Supported Protocols
376
+
377
+ ```
378
+ GET /workflows/:workflowId/exchanges/:exchangeId/protocols
379
+ ```
380
+
381
+ Returns a `{"protocols": {...}}` object listing all interaction URLs supported
382
+ by the exchange. Key names are:
383
+ - `vcapi` — always this literal string when VC-API is supported
384
+ - `inviteRequest` — always this literal string when an invite request step is active
385
+ - OID4VCI — always `OID4VCI`
386
+ - OID4VP — defaults to `OID4VP` but is controlled by the `protocolUrlParameters.name`
387
+ field on each OID4VP client profile, so named profiles may produce arbitrary keys
388
+ (e.g. a profile with `"name": "bar"` produces a `bar` key)
389
+
390
+ ### OID4VCI Endpoints
391
+
392
+ The well-known metadata endpoints are served at **two URL shapes** for maximum
393
+ wallet compatibility:
394
+
395
+ | Method | Path | Description |
396
+ |--------|------|-------------|
397
+ | `GET` | `/.well-known/openid-credential-issuer/workflows/:wfId/exchanges/:id` | Credential issuer metadata (prefix form) |
398
+ | `GET` | `/workflows/:wfId/exchanges/:id/.well-known/openid-credential-issuer` | Credential issuer metadata (suffix form) |
399
+ | `GET` | `/.well-known/oauth-authorization-server/workflows/:wfId/exchanges/:id` | AS metadata (prefix form) |
400
+ | `GET` | `/workflows/:wfId/exchanges/:id/.well-known/oauth-authorization-server` | AS metadata (suffix form) |
401
+ | `GET` | `…/exchanges/:id/openid/credential-offer` | Credential offer object |
402
+ | `POST` | `…/exchanges/:id/openid/token` | Access token endpoint |
403
+ | `POST` | `…/exchanges/:id/openid/credential` | Credential request endpoint |
404
+ | `POST` | `…/exchanges/:id/openid/batch_credential` | Batch credential requests |
405
+ | `GET` | `…/exchanges/:id/openid/jwks` | JSON Web Key Set |
406
+ | `POST` | `…/exchanges/:id/openid/nonce` | Nonce endpoint |
407
+
408
+ ### OID4VP Endpoints
409
+
410
+ Legacy (no client profile ID) and modern (with client profile ID) routes are
411
+ both supported:
412
+
413
+ | Method | Path | Description |
414
+ |--------|------|-------------|
415
+ | `GET/POST` | `…/exchanges/:id/openid/client/authorization/request` | Retrieve authorization request (default profile) |
416
+ | `POST` | `…/exchanges/:id/openid/client/authorization/response` | Submit authorization response (default profile) |
417
+ | `GET/POST` | `…/exchanges/:id/openid/clients/:clientProfileId/authorization/request` | Retrieve authorization request (named profile) |
418
+ | `POST` | `…/exchanges/:id/openid/clients/:clientProfileId/authorization/response` | Submit authorization response (named profile) |
419
+
420
+ ### Invite Request Endpoints
421
+
422
+ | Method | Path | Description |
423
+ |--------|------|-------------|
424
+ | `POST` | `…/exchanges/:id/invite-request/response` | Submit invite response |
425
+
426
+ ## Supported Protocols
427
+
428
+ ### VC-API
429
+
430
+ The [VC-API][] protocol is automatically supported for any workflow that has
431
+ `credentialTemplates`, or for any step that has a
432
+ `verifiablePresentationRequest` or `verifiablePresentation`. The exchange URL
433
+ itself serves as the `vcapi` interaction endpoint.
434
+
435
+ ### OID4VCI
436
+
437
+ [OpenID for Verifiable Credential Issuance][OID4VCI-spec] is supported when
438
+ an exchange is created with an `openId` configuration object. Supported grant
439
+ types:
440
+
441
+ - Pre-authorized code flow (`urn:ietf:params:oauth:grant-type:pre-authorized_code`)
442
+
443
+ Supported proof types for credential requests:
444
+
445
+ - `jwt` (JWT-based DID proof)
446
+ - `di_vp` (Data Integrity VP DID proof)
447
+
448
+ Supported credential formats (OID4VCI v1.0):
449
+
450
+ - `ldp_vc` / `application/vc` (JSON-LD Verifiable Credential)
451
+ - `jwt_vc_json` / `application/jwt` (JWT Verifiable Credential)
452
+
453
+ Supported for backwards compatibility with OID4VCI Draft 13 (deprecated):
454
+
455
+ - `jwt_vc_json-ld` (JSON-LD-based VC-JWT envelope)
456
+
457
+ > **Deprecated:** OID4VCI Draft 13 credential request formats are supported
458
+ > for backwards compatibility but are deprecated. New implementations should
459
+ > use OID4VCI v1.0.
460
+
461
+ ### OID4VP
462
+
463
+ [OpenID for Verifiable Presentations][OID4VP-spec] is supported when a step
464
+ includes an `openId` configuration. The module supports:
465
+
466
+ - OID4VP 1.0+ (with prefixed `client_id` schemes and `request_uri_method=post`)
467
+ - Signed authorization requests (via `authorizationRequestSigningParameters`)
468
+ - Multiple response modes: `direct_post`, `direct_post.jwt`, `dc_api`, `dc_api.jwt`
469
+ - mDL / ISO 18013-7 presentations (Annex B, C, and D handover types)
470
+ - DCQL queries (`dcql_query`)
471
+
472
+ Supported for backwards compatibility (deprecated):
473
+
474
+ - OID4VP Draft 18
475
+ - Presentation Definitions (`presentation_definition`)
476
+
477
+ ### Invite Request
478
+
479
+ A lightweight invite-based protocol. When a step exposes an `inviteRequest`
480
+ property, the exchange will include an `inviteRequest` URL in its `protocols`
481
+ response. The client POSTs an invite response (containing a `url`, `purpose`,
482
+ and optional `referenceId`) to complete this step.
483
+
484
+ Because the static `computedStep` schema does not declare an `inviteRequest`
485
+ property (it uses `additionalProperties: false`), the property must be injected
486
+ at runtime via a `stepTemplate` rather than declared directly in the workflow
487
+ configuration:
488
+
489
+ ```js
490
+ "steps": {
491
+ "myStep": {
492
+ "stepTemplate": {
493
+ "type": "jsonata",
494
+ "template": "{ \"inviteRequest\": inviteRequest }"
495
+ }
496
+ }
497
+ }
498
+ ```
499
+
500
+ The exchange variable `inviteRequest` must be set to `true` when creating the
501
+ exchange to activate the invite request protocol for that step.
502
+
503
+ ## Exchange Lifecycle
504
+
505
+ ```mermaid
506
+ graph TD
507
+ A[Create Exchange]:::accent0 --> B[Exchange Pending]:::accent1
508
+ B --> C{Protocol}:::accent2
509
+ C -->|VC-API| D[POST to exchange URL]
510
+ C -->|OID4VCI| E[Pre-auth code flow]
511
+ C -->|OID4VP| F[Fetch authz request]
512
+ C -->|Invite| G[POST invite response]
513
+ D & E & F & G --> H{Step complete?}:::accent3
514
+ H -->|Next step exists| B
515
+ H -->|No more steps| I[Exchange Complete]:::accent4
516
+ B -->|TTL expires| J[Exchange Expired]:::accent5
517
+ ```
518
+
519
+ Exchanges are stored in MongoDB. By default they expire after **15 minutes**
520
+ (`ttl: 900`). The maximum TTL is **48 hours** (`ttl: 172800`). Expired
521
+ exchanges are retained for an additional grace period of 3 days before being
522
+ eligible for removal.
523
+
524
+ Exchange `variables` hold the mutable state that flows between steps, including
525
+ per-step results accessible at `variables.results[stepName]`.
526
+
527
+ ## Multi-Step Workflows
528
+
529
+ A workflow can chain multiple steps using the `nextStep` field. This enables
530
+ patterns such as:
531
+
532
+ 1. **Verify then Issue** — Require the holder to present an existing credential
533
+ before receiving a new one.
534
+ 2. **OID4VP then OID4VCI** — Verify via OID4VP and then issue via OID4VCI in
535
+ the same exchange session.
536
+ 3. **Invite then Issue** — Collect wallet/app metadata via invite request
537
+ before issuing credentials.
538
+
539
+ Step results are stored in `exchange.variables.results[stepName]` and are
540
+ accessible in subsequent JSONata step templates or credential templates.
541
+
542
+ ## Security
543
+
544
+ - Workflow management routes require **zcap** or **OAuth2** authorization.
545
+ - Exchange execution routes (VC-API `POST`) are unauthenticated by design,
546
+ relying on capability URLs for authorization; exchanges are single-use,
547
+ short-lived, and scoped to a specific workflow. Workflows themselves
548
+ can add authentication by asking for verifiable presentations and
549
+ verifiable credentials.
550
+ - CORS is enabled on all endpoints. This is safe because authorization is
551
+ performed using HTTP signatures and capabilities (not cookies), making CSRF
552
+ impossible.
553
+ - Private key material (`privateKeyJwk`) and exchange `secrets` are stripped
554
+ from all API responses.
555
+ - VC-API exchange creation and exchange-use payloads are limited to **10 MB** (configured via `config.express.bodyParser.routes`). OID4VP authorization-response form posts are also limited to **10 MB** (via an inline `urlencoded` body parser). Other OID4VCI endpoints (token, credential, etc.) rely on the framework's default body-size limits. A feature exists to enable larger exchange state, but it has not been enabled at this time.
556
+
557
+ ## Backwards Compatibility
558
+
559
+ This module previously exposed a `vc-exchanger` service at `/exchangers`. That
560
+ service type and route prefix are still registered as aliases and will continue
561
+ to function, but new deployments should use `vc-workflow` and `/workflows`.
562
+
563
+ ## License
564
+
565
+ [New BSD License](LICENSE.md) © 2022-2026 Digital Bazaar, Inc.
566
+
567
+ [Bedrock]: https://github.com/digitalbazaar/bedrock
568
+ [JSONata]: https://jsonata.org
569
+ [VC-API]: https://w3c-ccg.github.io/vc-api/
570
+ [OID4VCI-spec]: https://openid.net/specs/openid-4-verifiable-credential-issuance-1_0.html
571
+ [OID4VP-spec]: https://openid.net/specs/openid-4-verifiable-presentations-1_0.html
572
+ [`@bedrock/mongodb`]: https://github.com/digitalbazaar/bedrock-mongodb
573
+ [`@bedrock/service-core`]: https://github.com/digitalbazaar/bedrock-service-core
@@ -183,7 +183,7 @@ export async function get({
183
183
  }
184
184
 
185
185
  let record = await collection.findOne(query, {projection});
186
- if(!allowExpired) {
186
+ if(record && !allowExpired) {
187
187
  // ensure `expires` is enforced programmatically even if background job
188
188
  // has not yet removed the record; force unexpiring exchanges to be not
189
189
  // found via this code path -- any exchanges without an expiration date
@@ -191,7 +191,7 @@ export async function get({
191
191
  // in the database
192
192
  const now = new Date();
193
193
  // note: for undefined `expires`, this will be `NaN || now` => `now`
194
- const expires = new Date(record.exchange.expires) || now;
194
+ const expires = new Date(Date.parse(record.exchange.expires) || now);
195
195
  if(now >= expires) {
196
196
  record = null;
197
197
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bedrock/vc-delivery",
3
- "version": "7.16.0",
3
+ "version": "7.16.1",
4
4
  "type": "module",
5
5
  "description": "Bedrock Verifiable Credential Delivery",
6
6
  "main": "./lib/index.js",