@sd-jwt/sd-jwt-vc 0.12.1-next.1 → 0.12.1-next.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/dist/index.d.mts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { SDJWTConfig, kbPayload, kbHeader, DisclosureFrame } from '@sd-jwt/types';
2
- import { SdJwtPayload, SDJwtInstance } from '@sd-jwt/core';
2
+ import { SdJwtPayload, SDJwtInstance, VerifierOptions } from '@sd-jwt/core';
3
3
 
4
4
  /**
5
5
  * Logo metadata used in rendering a credential.
@@ -217,7 +217,7 @@ declare class SDJwtVcInstance extends SDJwtInstance<SdJwtVcPayload> {
217
217
  * Verifies the SD-JWT-VC. It will validate the signature, the keybindings when required, the status, and the VCT.
218
218
  * @param currentDate current time in seconds
219
219
  */
220
- verify(encodedSDJwt: string, requiredClaimKeys?: string[], requireKeyBindings?: boolean, currentDate?: number): Promise<VerificationResult>;
220
+ verify(encodedSDJwt: string, requiredClaimKeys?: string[], requireKeyBindings?: boolean, options?: VerifierOptions): Promise<VerificationResult>;
221
221
  /**
222
222
  * Gets VCT Metadata of the raw SD-JWT-VC. Returns the type metadata format. If the SD-JWT-VC is invalid or does not contain a vct claim, an error is thrown.
223
223
  * @param encodedSDJwt
@@ -254,10 +254,16 @@ declare class SDJwtVcInstance extends SDJwtInstance<SdJwtVcPayload> {
254
254
  * @returns
255
255
  */
256
256
  private fetchVct;
257
+ /**
258
+ * Fetches VCT Metadata from the header of the SD-JWT-VC. Returns the type metadata format. If the SD-JWT-VC does not contain a vct claim, an error is thrown.
259
+ * @param result
260
+ * @param
261
+ */
262
+ private fetchVctFromHeader;
257
263
  /**
258
264
  * Verifies the status of the SD-JWT-VC.
259
265
  * @param result
260
- * @param currentDate current time in seconds
266
+ * @param options
261
267
  */
262
268
  private verifyStatus;
263
269
  }
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { SDJWTConfig, kbPayload, kbHeader, DisclosureFrame } from '@sd-jwt/types';
2
- import { SdJwtPayload, SDJwtInstance } from '@sd-jwt/core';
2
+ import { SdJwtPayload, SDJwtInstance, VerifierOptions } from '@sd-jwt/core';
3
3
 
4
4
  /**
5
5
  * Logo metadata used in rendering a credential.
@@ -217,7 +217,7 @@ declare class SDJwtVcInstance extends SDJwtInstance<SdJwtVcPayload> {
217
217
  * Verifies the SD-JWT-VC. It will validate the signature, the keybindings when required, the status, and the VCT.
218
218
  * @param currentDate current time in seconds
219
219
  */
220
- verify(encodedSDJwt: string, requiredClaimKeys?: string[], requireKeyBindings?: boolean, currentDate?: number): Promise<VerificationResult>;
220
+ verify(encodedSDJwt: string, requiredClaimKeys?: string[], requireKeyBindings?: boolean, options?: VerifierOptions): Promise<VerificationResult>;
221
221
  /**
222
222
  * Gets VCT Metadata of the raw SD-JWT-VC. Returns the type metadata format. If the SD-JWT-VC is invalid or does not contain a vct claim, an error is thrown.
223
223
  * @param encodedSDJwt
@@ -254,10 +254,16 @@ declare class SDJwtVcInstance extends SDJwtInstance<SdJwtVcPayload> {
254
254
  * @returns
255
255
  */
256
256
  private fetchVct;
257
+ /**
258
+ * Fetches VCT Metadata from the header of the SD-JWT-VC. Returns the type metadata format. If the SD-JWT-VC does not contain a vct claim, an error is thrown.
259
+ * @param result
260
+ * @param
261
+ */
262
+ private fetchVctFromHeader;
257
263
  /**
258
264
  * Verifies the status of the SD-JWT-VC.
259
265
  * @param result
260
- * @param currentDate current time in seconds
266
+ * @param options
261
267
  */
262
268
  private verifyStatus;
263
269
  }
package/dist/index.js CHANGED
@@ -131,8 +131,8 @@ var SDJwtVcInstance = class _SDJwtVcInstance extends import_core.SDJwtInstance {
131
131
  * Verifies the SD-JWT-VC. It will validate the signature, the keybindings when required, the status, and the VCT.
132
132
  * @param currentDate current time in seconds
133
133
  */
134
- verify(_0, _1, _2) {
135
- return __async(this, arguments, function* (encodedSDJwt, requiredClaimKeys, requireKeyBindings, currentDate = Math.floor(Date.now() / 1e3)) {
134
+ verify(encodedSDJwt, requiredClaimKeys, requireKeyBindings, options) {
135
+ return __async(this, null, function* () {
136
136
  const result = yield __superGet(_SDJwtVcInstance.prototype, this, "verify").call(this, encodedSDJwt, requiredClaimKeys, requireKeyBindings).then((res) => {
137
137
  return {
138
138
  payload: res.payload,
@@ -140,7 +140,7 @@ var SDJwtVcInstance = class _SDJwtVcInstance extends import_core.SDJwtInstance {
140
140
  kb: res.kb
141
141
  };
142
142
  });
143
- yield this.verifyStatus(result, currentDate);
143
+ yield this.verifyStatus(result, options);
144
144
  if (this.userConfig.loadTypeMetadataFormat) {
145
145
  yield this.verifyVct(result);
146
146
  }
@@ -281,22 +281,51 @@ var SDJwtVcInstance = class _SDJwtVcInstance extends import_core.SDJwtInstance {
281
281
  */
282
282
  fetchVct(result) {
283
283
  return __async(this, null, function* () {
284
- var _a;
284
+ var _a, _b;
285
285
  if (!result.payload.vct) {
286
286
  throw new import_utils.SDJWTException("vct claim is required");
287
287
  }
288
- const fetcher = (_a = this.userConfig.vctFetcher) != null ? _a : (uri, integrity) => this.fetch(uri, integrity);
288
+ if ((_a = result.header) == null ? void 0 : _a.vctm) {
289
+ return this.fetchVctFromHeader(result.payload.vct, result);
290
+ }
291
+ const fetcher = (_b = this.userConfig.vctFetcher) != null ? _b : (uri, integrity) => this.fetch(uri, integrity);
289
292
  return fetcher(result.payload.vct, result.payload["vct#Integrity"]);
290
293
  });
291
294
  }
295
+ /**
296
+ * Fetches VCT Metadata from the header of the SD-JWT-VC. Returns the type metadata format. If the SD-JWT-VC does not contain a vct claim, an error is thrown.
297
+ * @param result
298
+ * @param
299
+ */
300
+ fetchVctFromHeader(vct, result) {
301
+ return __async(this, null, function* () {
302
+ var _a;
303
+ const vctmHeader = (_a = result.header) == null ? void 0 : _a.vctm;
304
+ if (!vctmHeader || !Array.isArray(vctmHeader)) {
305
+ throw new Error("vctm claim in SD JWT header is invalid");
306
+ }
307
+ const typeMetadataFormat = vctmHeader.map((vctm) => {
308
+ if (!(typeof vctm === "string")) {
309
+ throw new Error("vctm claim in SD JWT header is invalid");
310
+ }
311
+ return JSON.parse((0, import_utils.base64urlDecode)(vctm));
312
+ }).find((typeMetadataFormat2) => {
313
+ return typeMetadataFormat2.vct === vct;
314
+ });
315
+ if (!typeMetadataFormat) {
316
+ throw new Error("could not find VCT Metadata in JWT header");
317
+ }
318
+ return typeMetadataFormat;
319
+ });
320
+ }
292
321
  /**
293
322
  * Verifies the status of the SD-JWT-VC.
294
323
  * @param result
295
- * @param currentDate current time in seconds
324
+ * @param options
296
325
  */
297
- verifyStatus(result, currentDate) {
326
+ verifyStatus(result, options) {
298
327
  return __async(this, null, function* () {
299
- var _a, _b, _c;
328
+ var _a, _b, _c, _d;
300
329
  if (result.payload.status) {
301
330
  if (result.payload.status.status_list) {
302
331
  const fetcher = (_a = this.userConfig.statusListFetcher) != null ? _a : this.statusListFetcher.bind(this);
@@ -304,15 +333,16 @@ var SDJwtVcInstance = class _SDJwtVcInstance extends import_core.SDJwtInstance {
304
333
  result.payload.status.status_list.uri
305
334
  );
306
335
  const slJWT = import_core.Jwt.fromEncode(statusListJWT);
307
- yield slJWT.verify(this.userConfig.verifier, currentDate);
308
- if (((_b = slJWT.payload) == null ? void 0 : _b.exp) && slJWT.payload.exp < currentDate) {
336
+ yield slJWT.verify(this.userConfig.verifier, options);
337
+ const currentDate = (_b = options == null ? void 0 : options.currentDate) != null ? _b : Math.floor(Date.now() / 1e3);
338
+ if (((_c = slJWT.payload) == null ? void 0 : _c.exp) && slJWT.payload.exp < currentDate) {
309
339
  throw new import_utils.SDJWTException("Status list is expired");
310
340
  }
311
341
  const statusList = (0, import_jwt_status_list.getListFromStatusListJWT)(statusListJWT);
312
342
  const status = statusList.getStatus(
313
343
  result.payload.status.status_list.idx
314
344
  );
315
- const statusValidator = (_c = this.userConfig.statusValidator) != null ? _c : this.statusValidator.bind(this);
345
+ const statusValidator = (_d = this.userConfig.statusValidator) != null ? _d : this.statusValidator.bind(this);
316
346
  yield statusValidator(status);
317
347
  }
318
348
  }
package/dist/index.mjs CHANGED
@@ -24,7 +24,7 @@ var __async = (__this, __arguments, generator) => {
24
24
 
25
25
  // src/sd-jwt-vc-instance.ts
26
26
  import { Jwt, SDJwt, SDJwtInstance } from "@sd-jwt/core";
27
- import { SDJWTException } from "@sd-jwt/utils";
27
+ import { base64urlDecode, SDJWTException } from "@sd-jwt/utils";
28
28
  import {
29
29
  getListFromStatusListJWT
30
30
  } from "@sd-jwt/jwt-status-list";
@@ -99,8 +99,8 @@ var SDJwtVcInstance = class _SDJwtVcInstance extends SDJwtInstance {
99
99
  * Verifies the SD-JWT-VC. It will validate the signature, the keybindings when required, the status, and the VCT.
100
100
  * @param currentDate current time in seconds
101
101
  */
102
- verify(_0, _1, _2) {
103
- return __async(this, arguments, function* (encodedSDJwt, requiredClaimKeys, requireKeyBindings, currentDate = Math.floor(Date.now() / 1e3)) {
102
+ verify(encodedSDJwt, requiredClaimKeys, requireKeyBindings, options) {
103
+ return __async(this, null, function* () {
104
104
  const result = yield __superGet(_SDJwtVcInstance.prototype, this, "verify").call(this, encodedSDJwt, requiredClaimKeys, requireKeyBindings).then((res) => {
105
105
  return {
106
106
  payload: res.payload,
@@ -108,7 +108,7 @@ var SDJwtVcInstance = class _SDJwtVcInstance extends SDJwtInstance {
108
108
  kb: res.kb
109
109
  };
110
110
  });
111
- yield this.verifyStatus(result, currentDate);
111
+ yield this.verifyStatus(result, options);
112
112
  if (this.userConfig.loadTypeMetadataFormat) {
113
113
  yield this.verifyVct(result);
114
114
  }
@@ -249,22 +249,51 @@ var SDJwtVcInstance = class _SDJwtVcInstance extends SDJwtInstance {
249
249
  */
250
250
  fetchVct(result) {
251
251
  return __async(this, null, function* () {
252
- var _a;
252
+ var _a, _b;
253
253
  if (!result.payload.vct) {
254
254
  throw new SDJWTException("vct claim is required");
255
255
  }
256
- const fetcher = (_a = this.userConfig.vctFetcher) != null ? _a : (uri, integrity) => this.fetch(uri, integrity);
256
+ if ((_a = result.header) == null ? void 0 : _a.vctm) {
257
+ return this.fetchVctFromHeader(result.payload.vct, result);
258
+ }
259
+ const fetcher = (_b = this.userConfig.vctFetcher) != null ? _b : (uri, integrity) => this.fetch(uri, integrity);
257
260
  return fetcher(result.payload.vct, result.payload["vct#Integrity"]);
258
261
  });
259
262
  }
263
+ /**
264
+ * Fetches VCT Metadata from the header of the SD-JWT-VC. Returns the type metadata format. If the SD-JWT-VC does not contain a vct claim, an error is thrown.
265
+ * @param result
266
+ * @param
267
+ */
268
+ fetchVctFromHeader(vct, result) {
269
+ return __async(this, null, function* () {
270
+ var _a;
271
+ const vctmHeader = (_a = result.header) == null ? void 0 : _a.vctm;
272
+ if (!vctmHeader || !Array.isArray(vctmHeader)) {
273
+ throw new Error("vctm claim in SD JWT header is invalid");
274
+ }
275
+ const typeMetadataFormat = vctmHeader.map((vctm) => {
276
+ if (!(typeof vctm === "string")) {
277
+ throw new Error("vctm claim in SD JWT header is invalid");
278
+ }
279
+ return JSON.parse(base64urlDecode(vctm));
280
+ }).find((typeMetadataFormat2) => {
281
+ return typeMetadataFormat2.vct === vct;
282
+ });
283
+ if (!typeMetadataFormat) {
284
+ throw new Error("could not find VCT Metadata in JWT header");
285
+ }
286
+ return typeMetadataFormat;
287
+ });
288
+ }
260
289
  /**
261
290
  * Verifies the status of the SD-JWT-VC.
262
291
  * @param result
263
- * @param currentDate current time in seconds
292
+ * @param options
264
293
  */
265
- verifyStatus(result, currentDate) {
294
+ verifyStatus(result, options) {
266
295
  return __async(this, null, function* () {
267
- var _a, _b, _c;
296
+ var _a, _b, _c, _d;
268
297
  if (result.payload.status) {
269
298
  if (result.payload.status.status_list) {
270
299
  const fetcher = (_a = this.userConfig.statusListFetcher) != null ? _a : this.statusListFetcher.bind(this);
@@ -272,15 +301,16 @@ var SDJwtVcInstance = class _SDJwtVcInstance extends SDJwtInstance {
272
301
  result.payload.status.status_list.uri
273
302
  );
274
303
  const slJWT = Jwt.fromEncode(statusListJWT);
275
- yield slJWT.verify(this.userConfig.verifier, currentDate);
276
- if (((_b = slJWT.payload) == null ? void 0 : _b.exp) && slJWT.payload.exp < currentDate) {
304
+ yield slJWT.verify(this.userConfig.verifier, options);
305
+ const currentDate = (_b = options == null ? void 0 : options.currentDate) != null ? _b : Math.floor(Date.now() / 1e3);
306
+ if (((_c = slJWT.payload) == null ? void 0 : _c.exp) && slJWT.payload.exp < currentDate) {
277
307
  throw new SDJWTException("Status list is expired");
278
308
  }
279
309
  const statusList = getListFromStatusListJWT(statusListJWT);
280
310
  const status = statusList.getStatus(
281
311
  result.payload.status.status_list.idx
282
312
  );
283
- const statusValidator = (_c = this.userConfig.statusValidator) != null ? _c : this.statusValidator.bind(this);
313
+ const statusValidator = (_d = this.userConfig.statusValidator) != null ? _d : this.statusValidator.bind(this);
284
314
  yield statusValidator(status);
285
315
  }
286
316
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sd-jwt/sd-jwt-vc",
3
- "version": "0.12.1-next.1+0a2f20b",
3
+ "version": "0.12.1-next.3+f89ba44",
4
4
  "description": "sd-jwt draft 7 implementation in typescript",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -39,15 +39,15 @@
39
39
  },
40
40
  "license": "Apache-2.0",
41
41
  "dependencies": {
42
- "@sd-jwt/core": "0.12.1-next.1+0a2f20b",
43
- "@sd-jwt/jwt-status-list": "0.12.1-next.1+0a2f20b",
44
- "@sd-jwt/utils": "0.12.1-next.1+0a2f20b",
42
+ "@sd-jwt/core": "0.12.1-next.3+f89ba44",
43
+ "@sd-jwt/jwt-status-list": "0.12.1-next.3+f89ba44",
44
+ "@sd-jwt/utils": "0.12.1-next.3+f89ba44",
45
45
  "ajv": "^8.17.1",
46
46
  "ajv-formats": "^3.0.1"
47
47
  },
48
48
  "devDependencies": {
49
- "@sd-jwt/crypto-nodejs": "0.12.1-next.1+0a2f20b",
50
- "@sd-jwt/types": "0.12.1-next.1+0a2f20b",
49
+ "@sd-jwt/crypto-nodejs": "0.12.1-next.3+f89ba44",
50
+ "@sd-jwt/types": "0.12.1-next.3+f89ba44",
51
51
  "jose": "^5.2.2",
52
52
  "msw": "^2.3.5"
53
53
  },
@@ -67,5 +67,5 @@
67
67
  "esm"
68
68
  ]
69
69
  },
70
- "gitHead": "0a2f20b6383d2356540e7a9cc37748c7b9caced2"
70
+ "gitHead": "f89ba445aeb57ce342ec76b58a0eb6d0c090a4e9"
71
71
  }
@@ -1,6 +1,6 @@
1
- import { Jwt, SDJwt, SDJwtInstance } from '@sd-jwt/core';
1
+ import { Jwt, SDJwt, SDJwtInstance, type VerifierOptions } from '@sd-jwt/core';
2
2
  import type { DisclosureFrame, Hasher, Verifier } from '@sd-jwt/types';
3
- import { SDJWTException } from '@sd-jwt/utils';
3
+ import { base64urlDecode, SDJWTException } from '@sd-jwt/utils';
4
4
  import type { SdJwtVcPayload } from './sd-jwt-vc-payload';
5
5
  import type {
6
6
  SDJWTVCConfig,
@@ -110,9 +110,10 @@ export class SDJwtVcInstance extends SDJwtInstance<SdJwtVcPayload> {
110
110
  */
111
111
  async verify(
112
112
  encodedSDJwt: string,
113
+ //TODO: we need to move these values in options, causing a breaking change
113
114
  requiredClaimKeys?: string[],
114
115
  requireKeyBindings?: boolean,
115
- currentDate: number = Math.floor(Date.now() / 1000),
116
+ options?: VerifierOptions,
116
117
  ) {
117
118
  // Call the parent class's verify method
118
119
  const result: VerificationResult = await super
@@ -125,7 +126,7 @@ export class SDJwtVcInstance extends SDJwtInstance<SdJwtVcPayload> {
125
126
  };
126
127
  });
127
128
 
128
- await this.verifyStatus(result, currentDate);
129
+ await this.verifyStatus(result, options);
129
130
  if (this.userConfig.loadTypeMetadataFormat) {
130
131
  await this.verifyVct(result);
131
132
  }
@@ -293,20 +294,58 @@ export class SDJwtVcInstance extends SDJwtInstance<SdJwtVcPayload> {
293
294
  throw new SDJWTException('vct claim is required');
294
295
  }
295
296
 
297
+ if (result.header?.vctm) {
298
+ return this.fetchVctFromHeader(result.payload.vct, result);
299
+ }
300
+
296
301
  const fetcher: VcTFetcher =
297
302
  this.userConfig.vctFetcher ??
298
303
  ((uri, integrity) => this.fetch(uri, integrity));
299
304
  return fetcher(result.payload.vct, result.payload['vct#Integrity']);
300
305
  }
301
306
 
307
+ /**
308
+ * Fetches VCT Metadata from the header of the SD-JWT-VC. Returns the type metadata format. If the SD-JWT-VC does not contain a vct claim, an error is thrown.
309
+ * @param result
310
+ * @param
311
+ */
312
+ private async fetchVctFromHeader(
313
+ vct: string,
314
+ result: VerificationResult,
315
+ ): Promise<TypeMetadataFormat> {
316
+ const vctmHeader = result.header?.vctm;
317
+
318
+ if (!vctmHeader || !Array.isArray(vctmHeader)) {
319
+ throw new Error('vctm claim in SD JWT header is invalid');
320
+ }
321
+
322
+ const typeMetadataFormat = (vctmHeader as unknown[])
323
+ .map((vctm) => {
324
+ if (!(typeof vctm === 'string')) {
325
+ throw new Error('vctm claim in SD JWT header is invalid');
326
+ }
327
+
328
+ return JSON.parse(base64urlDecode(vctm));
329
+ })
330
+ .find((typeMetadataFormat) => {
331
+ return typeMetadataFormat.vct === vct;
332
+ });
333
+
334
+ if (!typeMetadataFormat) {
335
+ throw new Error('could not find VCT Metadata in JWT header');
336
+ }
337
+
338
+ return typeMetadataFormat;
339
+ }
340
+
302
341
  /**
303
342
  * Verifies the status of the SD-JWT-VC.
304
343
  * @param result
305
- * @param currentDate current time in seconds
344
+ * @param options
306
345
  */
307
346
  private async verifyStatus(
308
347
  result: VerificationResult,
309
- currentDate: number,
348
+ options?: VerifierOptions,
310
349
  ): Promise<void> {
311
350
  if (result.payload.status) {
312
351
  //checks if a status field is present in the payload based on https://www.ietf.org/archive/id/draft-ietf-oauth-status-list-02.html
@@ -325,8 +364,10 @@ export class SDJwtVcInstance extends SDJwtInstance<SdJwtVcPayload> {
325
364
  StatusListJWTPayload
326
365
  >(statusListJWT);
327
366
  // check if the status list has a valid signature. The presence of the verifier is checked in the parent class.
328
- await slJWT.verify(this.userConfig.verifier as Verifier, currentDate);
367
+ await slJWT.verify(this.userConfig.verifier as Verifier, options);
329
368
 
369
+ const currentDate =
370
+ options?.currentDate ?? Math.floor(Date.now() / 1000);
330
371
  //check if the status list is expired
331
372
  if (slJWT.payload?.exp && (slJWT.payload.exp as number) < currentDate) {
332
373
  throw new SDJWTException('Status list is expired');
@@ -9,6 +9,16 @@ import { HttpResponse, http } from 'msw';
9
9
  import { afterEach } from 'node:test';
10
10
  import type { TypeMetadataFormat } from '../sd-jwt-vc-type-metadata-format';
11
11
 
12
+ const exampleVctm = {
13
+ vct: 'http://example.com/example',
14
+ name: 'ExampleCredentialType',
15
+ description: 'An example credential type',
16
+ schema_uri: 'http://example.com/schema/example',
17
+ //this value could be generated on demand to make it easier when changing the values
18
+ 'schema_uri#Integrity':
19
+ 'sha256-48a61b283ded3b55e8d9a9b063327641dc4c53f76bd5daa96c23f232822167ae',
20
+ };
21
+
12
22
  const restHandlers = [
13
23
  http.get('http://example.com/schema/example', () => {
14
24
  const res = {
@@ -42,15 +52,7 @@ const restHandlers = [
42
52
  return HttpResponse.json(res);
43
53
  }),
44
54
  http.get('http://example.com/example', () => {
45
- const res: TypeMetadataFormat = {
46
- vct: 'http://example.com/example',
47
- name: 'ExampleCredentialType',
48
- description: 'An example credential type',
49
- schema_uri: 'http://example.com/schema/example',
50
- //this value could be generated on demand to make it easier when changing the values
51
- 'schema_uri#Integrity':
52
- 'sha256-48a61b283ded3b55e8d9a9b063327641dc4c53f76bd5daa96c23f232822167ae',
53
- };
55
+ const res: TypeMetadataFormat = exampleVctm;
54
56
  return HttpResponse.json(res);
55
57
  }),
56
58
  http.get('http://example.com/timeout', () => {
@@ -133,6 +135,26 @@ describe('App', () => {
133
135
  await sdjwt.verify(encodedSdjwt);
134
136
  });
135
137
 
138
+ test('VCT from JWT header Validation', async () => {
139
+ const expectedPayload: SdJwtVcPayload = {
140
+ iat,
141
+ iss,
142
+ vct,
143
+ 'vct#Integrity': vctIntegrity,
144
+ ...claims,
145
+ };
146
+ const header = {
147
+ vctm: [Buffer.from(JSON.stringify(exampleVctm)).toString('base64url')],
148
+ };
149
+ const encodedSdjwt = await sdjwt.issue(
150
+ expectedPayload,
151
+ disclosureFrame as unknown as DisclosureFrame<SdJwtVcPayload>,
152
+ { header },
153
+ );
154
+
155
+ await sdjwt.verify(encodedSdjwt);
156
+ });
157
+
136
158
  test('VCT Validation with timeout', async () => {
137
159
  const vct = 'http://example.com/timeout';
138
160
  const expectedPayload: SdJwtVcPayload = {