@sd-jwt/core 0.19.1-next.9 → 0.20.1-next.0

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/CHANGELOG.md ADDED
@@ -0,0 +1,28 @@
1
+ # Change Log
2
+
3
+ All notable changes to this project will be documented in this file.
4
+ See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
+
6
+ # [0.20.0](https://github.com/openwallet-foundation/sd-jwt-js/compare/v0.1.0...v0.20.0) (2026-06-29)
7
+
8
+
9
+ ### Features
10
+
11
+ * version fixing to current 0.19.0 ([#382](https://github.com/openwallet-foundation/sd-jwt-js/issues/382)) ([d88c631](https://github.com/openwallet-foundation/sd-jwt-js/commit/d88c631fe4c3cefcbc96f268cb9d340296facbba))
12
+
13
+
14
+
15
+
16
+
17
+ # [0.1.0](https://github.com/openwallet-foundation/sd-jwt-js/compare/v0.19.0...v0.1.0) (2026-06-29)
18
+
19
+
20
+ ### Bug Fixes
21
+
22
+ * **core:** reject tampered/unreferenced disclosures and reserved claims ([#380](https://github.com/openwallet-foundation/sd-jwt-js/issues/380)) ([3d8a72a](https://github.com/openwallet-foundation/sd-jwt-js/commit/3d8a72a0a279d67439db038c9c2b52621568b866))
23
+ * verify common jwt claims for kb-jwt ([#378](https://github.com/openwallet-foundation/sd-jwt-js/issues/378)) ([9e9bca1](https://github.com/openwallet-foundation/sd-jwt-js/commit/9e9bca10de3ad8574bfcbc875c85e37cee541505))
24
+
25
+
26
+ ### Features
27
+
28
+ * allow disabling status verification ([#381](https://github.com/openwallet-foundation/sd-jwt-js/issues/381)) ([c9d73e4](https://github.com/openwallet-foundation/sd-jwt-js/commit/c9d73e4db2a925e5096988fffe7eded62db1b6a7))
package/dist/index.d.mts CHANGED
@@ -336,6 +336,12 @@ type VerifierOptions = {
336
336
  * nonce used to verify the key binding jwt to prevent replay attacks.
337
337
  */
338
338
  keyBindingNonce?: string;
339
+ /**
340
+ * disable the verification of the status claim in the payload.
341
+ *
342
+ * @default false
343
+ */
344
+ disableStatusVerification?: boolean;
339
345
  /**
340
346
  * any other custom options
341
347
  */
@@ -376,6 +382,11 @@ declare class KBJwt<Header extends kbHeader = kbHeader, Payload extends kbPayloa
376
382
  verifier: KbVerifier;
377
383
  payload: Record<string, unknown>;
378
384
  nonce: string;
385
+ /**
386
+ * Options forwarded to the common JWT verification, e.g. currentDate and
387
+ * skewSeconds used to validate the iat, nbf and exp claims.
388
+ */
389
+ options?: VerifierOptions;
379
390
  }): Promise<{
380
391
  payload: Payload;
381
392
  header: Header;
@@ -537,11 +548,12 @@ declare class SDJwtInstance<ExtendedPayload extends SdJwtPayload, T = unknown> {
537
548
  header?: object;
538
549
  }): Promise<SDJWTCompact>;
539
550
  /**
540
- * Validates if the disclosureFrame contains any reserved fields. If so it will throw an error.
541
- * @param disclosureFrame
551
+ * Validates if the payload contains any reserved claim names. If so it will throw an error.
552
+ * @param payload
542
553
  * @returns
543
554
  */
544
- protected validateReservedFields<T extends ExtendedPayload>(_disclosureFrame: DisclosureFrame<T>): void;
555
+ protected validateReservedFields<T extends ExtendedPayload>(payload: T): void;
556
+ protected validateDisclosureFrame<T extends ExtendedPayload>(_disclosureFrame?: DisclosureFrame<T>): void;
545
557
  present<T extends Record<string, unknown>>(encodedSDJwt: string, presentationFrame?: PresentationFrame<T>, options?: {
546
558
  kb?: KBOptions;
547
559
  }): Promise<SDJWTCompact>;
@@ -610,21 +622,22 @@ declare class SDJwtGeneralJSONInstance<ExtendedPayload extends SdJwtPayload> {
610
622
  }>;
611
623
  }): Promise<GeneralJSON>;
612
624
  /**
613
- * Validates if the disclosureFrame contains any reserved fields. If so it will throw an error.
614
- * @param disclosureFrame
625
+ * Validates if the payload contains any reserved claim names. If so it will throw an error.
626
+ * @param payload
615
627
  * @returns
616
628
  */
617
- protected validateReservedFields<T extends ExtendedPayload>(_disclosureFrame: DisclosureFrame<T>): void;
629
+ protected validateReservedFields<T extends ExtendedPayload>(payload: T): void;
630
+ protected validateDisclosureFrame<T extends ExtendedPayload>(_disclosureFrame?: DisclosureFrame<T>): void;
618
631
  present<T extends Record<string, unknown>>(generalJSON: GeneralJSON, presentationFrame?: PresentationFrame<T>, options?: {
619
632
  kb?: KBOptions;
620
633
  }): Promise<GeneralJSON>;
621
634
  verify(generalJSON: GeneralJSON, options?: VerifierOptions): Promise<{
622
635
  payload: ExtendedPayload;
623
- headers: any[];
636
+ headers: unknown[];
624
637
  kb?: undefined;
625
638
  } | {
626
639
  payload: ExtendedPayload;
627
- headers: any[];
640
+ headers: unknown[];
628
641
  kb: {
629
642
  payload: kbPayload;
630
643
  header: kbHeader;
@@ -633,7 +646,7 @@ declare class SDJwtGeneralJSONInstance<ExtendedPayload extends SdJwtPayload> {
633
646
  private calculateSDHash;
634
647
  validate(generalJSON: GeneralJSON): Promise<{
635
648
  payload: ExtendedPayload;
636
- headers: any[];
649
+ headers: unknown[];
637
650
  }>;
638
651
  config(newConfig: SDJWTConfig): void;
639
652
  encode(sdJwt: GeneralJSON, index: number): SDJWTCompact;
package/dist/index.d.ts CHANGED
@@ -336,6 +336,12 @@ type VerifierOptions = {
336
336
  * nonce used to verify the key binding jwt to prevent replay attacks.
337
337
  */
338
338
  keyBindingNonce?: string;
339
+ /**
340
+ * disable the verification of the status claim in the payload.
341
+ *
342
+ * @default false
343
+ */
344
+ disableStatusVerification?: boolean;
339
345
  /**
340
346
  * any other custom options
341
347
  */
@@ -376,6 +382,11 @@ declare class KBJwt<Header extends kbHeader = kbHeader, Payload extends kbPayloa
376
382
  verifier: KbVerifier;
377
383
  payload: Record<string, unknown>;
378
384
  nonce: string;
385
+ /**
386
+ * Options forwarded to the common JWT verification, e.g. currentDate and
387
+ * skewSeconds used to validate the iat, nbf and exp claims.
388
+ */
389
+ options?: VerifierOptions;
379
390
  }): Promise<{
380
391
  payload: Payload;
381
392
  header: Header;
@@ -537,11 +548,12 @@ declare class SDJwtInstance<ExtendedPayload extends SdJwtPayload, T = unknown> {
537
548
  header?: object;
538
549
  }): Promise<SDJWTCompact>;
539
550
  /**
540
- * Validates if the disclosureFrame contains any reserved fields. If so it will throw an error.
541
- * @param disclosureFrame
551
+ * Validates if the payload contains any reserved claim names. If so it will throw an error.
552
+ * @param payload
542
553
  * @returns
543
554
  */
544
- protected validateReservedFields<T extends ExtendedPayload>(_disclosureFrame: DisclosureFrame<T>): void;
555
+ protected validateReservedFields<T extends ExtendedPayload>(payload: T): void;
556
+ protected validateDisclosureFrame<T extends ExtendedPayload>(_disclosureFrame?: DisclosureFrame<T>): void;
545
557
  present<T extends Record<string, unknown>>(encodedSDJwt: string, presentationFrame?: PresentationFrame<T>, options?: {
546
558
  kb?: KBOptions;
547
559
  }): Promise<SDJWTCompact>;
@@ -610,21 +622,22 @@ declare class SDJwtGeneralJSONInstance<ExtendedPayload extends SdJwtPayload> {
610
622
  }>;
611
623
  }): Promise<GeneralJSON>;
612
624
  /**
613
- * Validates if the disclosureFrame contains any reserved fields. If so it will throw an error.
614
- * @param disclosureFrame
625
+ * Validates if the payload contains any reserved claim names. If so it will throw an error.
626
+ * @param payload
615
627
  * @returns
616
628
  */
617
- protected validateReservedFields<T extends ExtendedPayload>(_disclosureFrame: DisclosureFrame<T>): void;
629
+ protected validateReservedFields<T extends ExtendedPayload>(payload: T): void;
630
+ protected validateDisclosureFrame<T extends ExtendedPayload>(_disclosureFrame?: DisclosureFrame<T>): void;
618
631
  present<T extends Record<string, unknown>>(generalJSON: GeneralJSON, presentationFrame?: PresentationFrame<T>, options?: {
619
632
  kb?: KBOptions;
620
633
  }): Promise<GeneralJSON>;
621
634
  verify(generalJSON: GeneralJSON, options?: VerifierOptions): Promise<{
622
635
  payload: ExtendedPayload;
623
- headers: any[];
636
+ headers: unknown[];
624
637
  kb?: undefined;
625
638
  } | {
626
639
  payload: ExtendedPayload;
627
- headers: any[];
640
+ headers: unknown[];
628
641
  kb: {
629
642
  payload: kbPayload;
630
643
  header: kbHeader;
@@ -633,7 +646,7 @@ declare class SDJwtGeneralJSONInstance<ExtendedPayload extends SdJwtPayload> {
633
646
  private calculateSDHash;
634
647
  validate(generalJSON: GeneralJSON): Promise<{
635
648
  payload: ExtendedPayload;
636
- headers: any[];
649
+ headers: unknown[];
637
650
  }>;
638
651
  config(newConfig: SDJWTConfig): void;
639
652
  encode(sdJwt: GeneralJSON, index: number): SDJWTCompact;
package/dist/index.js CHANGED
@@ -161,6 +161,18 @@ function ensureError(value) {
161
161
  return new Error(String(value));
162
162
  }
163
163
 
164
+ // src/utils/strict-json.ts
165
+ var utf8Decoder = new TextDecoder("utf-8", { fatal: true });
166
+ var decodeBase64urlJsonStrict = (encoded, errorMessage) => {
167
+ try {
168
+ const bytes = (0, import_identity_common.base64UrlToUint8Array)(encoded);
169
+ const decoded = utf8Decoder.decode(bytes);
170
+ return JSON.parse(decoded);
171
+ } catch (e) {
172
+ throw new SDJWTException(errorMessage);
173
+ }
174
+ };
175
+
164
176
  // src/utils/disclosure.ts
165
177
  var Disclosure = class _Disclosure {
166
178
  constructor(data, _meta) {
@@ -187,7 +199,10 @@ var Disclosure = class _Disclosure {
187
199
  const { hasher, alg } = hash;
188
200
  const digest = yield hasher(s, alg);
189
201
  const digestStr = (0, import_identity_common.uint8ArrayToBase64Url)(digest);
190
- const item = JSON.parse((0, import_identity_common.base64urlDecode)(s));
202
+ const item = decodeBase64urlJsonStrict(
203
+ s,
204
+ "Invalid disclosure data"
205
+ );
191
206
  return _Disclosure.fromArray(item, { digest: digestStr, encoded: s });
192
207
  });
193
208
  }
@@ -195,7 +210,10 @@ var Disclosure = class _Disclosure {
195
210
  const { hasher, alg } = hash;
196
211
  const digest = hasher(s, alg);
197
212
  const digestStr = (0, import_identity_common.uint8ArrayToBase64Url)(digest);
198
- const item = JSON.parse((0, import_identity_common.base64urlDecode)(s));
213
+ const item = decodeBase64urlJsonStrict(
214
+ s,
215
+ "Invalid disclosure data"
216
+ );
199
217
  return _Disclosure.fromArray(item, { digest: digestStr, encoded: s });
200
218
  }
201
219
  static fromArray(item, _meta) {
@@ -237,8 +255,8 @@ var decodeJwt = (jwt) => {
237
255
  throw new SDJWTException("Invalid JWT as input");
238
256
  }
239
257
  return {
240
- header: JSON.parse((0, import_identity_common.base64urlDecode)(header)),
241
- payload: JSON.parse((0, import_identity_common.base64urlDecode)(payload)),
258
+ header: decodeBase64urlJsonStrict(header, "Invalid JWT as input"),
259
+ payload: decodeBase64urlJsonStrict(payload, "Invalid JWT as input"),
242
260
  signature
243
261
  };
244
262
  };
@@ -431,6 +449,11 @@ var getSDAlgAndPayload = (SdJwtPayload) => {
431
449
  if (typeof _sd_alg !== "string") {
432
450
  return { _sd_alg: "sha-256", payload };
433
451
  }
452
+ if (!IANA_HASH_ALGORITHMS.includes(
453
+ _sd_alg
454
+ )) {
455
+ throw new SDJWTException(`Invalid _sd_alg: ${_sd_alg}`);
456
+ }
434
457
  return { _sd_alg, payload };
435
458
  };
436
459
  var unpack = (SdJwtPayload, disclosures, hasher) => __async(null, null, function* () {
@@ -730,18 +753,13 @@ var KBJwt = class _KBJwt extends Jwt {
730
753
  !(this.payload.sd_hash || "_sd_hash" in this.payload && this.payload._sd_hash)) {
731
754
  throw new SDJWTException("Invalid Key Binding Jwt");
732
755
  }
733
- const data = this.getUnsignedToken();
734
- const verified = yield values.verifier(
735
- data,
736
- this.signature,
737
- values.payload
738
- );
739
- if (!verified) {
740
- throw new SDJWTException("Verify Error: Invalid JWT Signature");
741
- }
742
756
  if (this.payload.nonce !== values.nonce) {
743
757
  throw new SDJWTException("Verify Error: Invalid Nonce");
744
758
  }
759
+ yield this.verify(
760
+ (data, sig) => values.verifier(data, sig, values.payload),
761
+ values.options
762
+ );
745
763
  return { payload: this.payload, header: this.header };
746
764
  });
747
765
  }
@@ -1160,9 +1178,8 @@ var _SDJwtInstance = class _SDJwtInstance {
1160
1178
  if (!this.userConfig.signAlg) {
1161
1179
  throw new SDJWTException("sign alogrithm not specified");
1162
1180
  }
1163
- if (disclosureFrame) {
1164
- this.validateReservedFields(disclosureFrame);
1165
- }
1181
+ this.validateReservedFields(payload);
1182
+ this.validateDisclosureFrame(disclosureFrame);
1166
1183
  const hasher = this.userConfig.hasher;
1167
1184
  const hashAlg = (_a = this.userConfig.hashAlg) != null ? _a : _SDJwtInstance.DEFAULT_hashAlg;
1168
1185
  const { packedClaims, disclosures } = yield pack(
@@ -1190,11 +1207,30 @@ var _SDJwtInstance = class _SDJwtInstance {
1190
1207
  });
1191
1208
  }
1192
1209
  /**
1193
- * Validates if the disclosureFrame contains any reserved fields. If so it will throw an error.
1194
- * @param disclosureFrame
1210
+ * Validates if the payload contains any reserved claim names. If so it will throw an error.
1211
+ * @param payload
1195
1212
  * @returns
1196
1213
  */
1197
- validateReservedFields(_disclosureFrame) {
1214
+ validateReservedFields(payload) {
1215
+ const reservedFields = /* @__PURE__ */ new Set([SD_DIGEST, "_sd_alg", SD_DECOY]);
1216
+ const visit = (node) => {
1217
+ if (!node || typeof node !== "object") {
1218
+ return;
1219
+ }
1220
+ for (const [key, value] of Object.entries(
1221
+ node
1222
+ )) {
1223
+ if (reservedFields.has(key)) {
1224
+ throw new SDJWTException(
1225
+ `Reserved field name "${key}" is not allowed`
1226
+ );
1227
+ }
1228
+ visit(value);
1229
+ }
1230
+ };
1231
+ visit(payload);
1232
+ }
1233
+ validateDisclosureFrame(_disclosureFrame) {
1198
1234
  return;
1199
1235
  }
1200
1236
  present(encodedSDJwt, presentationFrame, options) {
@@ -1259,7 +1295,8 @@ var _SDJwtInstance = class _SDJwtInstance {
1259
1295
  const kb = yield sdjwt.kbJwt.verifyKB({
1260
1296
  verifier: this.userConfig.kbVerifier,
1261
1297
  payload,
1262
- nonce: options.keyBindingNonce
1298
+ nonce: options.keyBindingNonce,
1299
+ options
1263
1300
  });
1264
1301
  if (!kb) {
1265
1302
  throw new Error("signature is not valid");
@@ -1390,7 +1427,8 @@ var _SDJwtInstance = class _SDJwtInstance {
1390
1427
  const kbResult = yield sdjwt.kbJwt.verifyKB({
1391
1428
  verifier: this.userConfig.kbVerifier,
1392
1429
  payload,
1393
- nonce: options.keyBindingNonce
1430
+ nonce: options.keyBindingNonce,
1431
+ options
1394
1432
  });
1395
1433
  if (!kbResult) {
1396
1434
  addError(
@@ -1568,9 +1606,8 @@ var SDJwtGeneralJSONInstance = class {
1568
1606
  if (!this.userConfig.saltGenerator) {
1569
1607
  throw new SDJWTException("SaltGenerator not found");
1570
1608
  }
1571
- if (disclosureFrame) {
1572
- this.validateReservedFields(disclosureFrame);
1573
- }
1609
+ this.validateReservedFields(payload);
1610
+ this.validateDisclosureFrame(disclosureFrame);
1574
1611
  const hasher = this.userConfig.hasher;
1575
1612
  const hashAlg = (_a = this.userConfig.hashAlg) != null ? _a : SDJwtInstance.DEFAULT_hashAlg;
1576
1613
  const { packedClaims, disclosures } = yield pack(
@@ -1579,10 +1616,12 @@ var SDJwtGeneralJSONInstance = class {
1579
1616
  { hasher, alg: hashAlg },
1580
1617
  this.userConfig.saltGenerator
1581
1618
  );
1582
- const encodedDisclosures = disclosures.map((d) => d.encode());
1583
1619
  const encodedSDJwtPayload = this.encodeObj(__spreadProps(__spreadValues({}, packedClaims), {
1584
1620
  _sd_alg: disclosureFrame ? hashAlg : void 0
1585
1621
  }));
1622
+ const encodedDisclosures = disclosures.map(
1623
+ (disclosure) => disclosure.encode()
1624
+ );
1586
1625
  const signatures = yield Promise.all(
1587
1626
  options.sigs.map((s) => __async(this, null, function* () {
1588
1627
  const { signer, alg, kid, header } = s;
@@ -1593,7 +1632,6 @@ var SDJwtGeneralJSONInstance = class {
1593
1632
  );
1594
1633
  return {
1595
1634
  protected: encodedProtectedHeader,
1596
- kid,
1597
1635
  signature
1598
1636
  };
1599
1637
  }))
@@ -1607,11 +1645,30 @@ var SDJwtGeneralJSONInstance = class {
1607
1645
  });
1608
1646
  }
1609
1647
  /**
1610
- * Validates if the disclosureFrame contains any reserved fields. If so it will throw an error.
1611
- * @param disclosureFrame
1648
+ * Validates if the payload contains any reserved claim names. If so it will throw an error.
1649
+ * @param payload
1612
1650
  * @returns
1613
1651
  */
1614
- validateReservedFields(_disclosureFrame) {
1652
+ validateReservedFields(payload) {
1653
+ const reservedFields = /* @__PURE__ */ new Set([SD_DIGEST, "_sd_alg", SD_DECOY]);
1654
+ const visit = (node) => {
1655
+ if (!node || typeof node !== "object") {
1656
+ return;
1657
+ }
1658
+ for (const [key, value] of Object.entries(
1659
+ node
1660
+ )) {
1661
+ if (reservedFields.has(key)) {
1662
+ throw new SDJWTException(
1663
+ `Reserved field name "${key}" is not allowed`
1664
+ );
1665
+ }
1666
+ visit(value);
1667
+ }
1668
+ };
1669
+ visit(payload);
1670
+ }
1671
+ validateDisclosureFrame(_disclosureFrame) {
1615
1672
  return;
1616
1673
  }
1617
1674
  present(generalJSON, presentationFrame, options) {
@@ -1690,7 +1747,8 @@ var SDJwtGeneralJSONInstance = class {
1690
1747
  const kb = yield sdjwt.kbJwt.verifyKB({
1691
1748
  verifier: this.userConfig.kbVerifier,
1692
1749
  payload,
1693
- nonce: options.keyBindingNonce
1750
+ nonce: options.keyBindingNonce,
1751
+ options
1694
1752
  });
1695
1753
  if (!kb) {
1696
1754
  throw new Error("signature is not valid");
@@ -1743,7 +1801,7 @@ var SDJwtGeneralJSONInstance = class {
1743
1801
  `${encodedHeader}.${payload}`,
1744
1802
  signature
1745
1803
  );
1746
- const header = JSON.parse((0, import_identity_common.base64urlDecode)(encodedHeader));
1804
+ const header = decodeBase64urlJsonStrict(encodedHeader, "Invalid JWT");
1747
1805
  return { verified: verified2, header };
1748
1806
  }))
1749
1807
  );
package/dist/index.mjs CHANGED
@@ -102,6 +102,18 @@ function ensureError(value) {
102
102
  return new Error(String(value));
103
103
  }
104
104
 
105
+ // src/utils/strict-json.ts
106
+ var utf8Decoder = new TextDecoder("utf-8", { fatal: true });
107
+ var decodeBase64urlJsonStrict = (encoded, errorMessage) => {
108
+ try {
109
+ const bytes = base64UrlToUint8Array(encoded);
110
+ const decoded = utf8Decoder.decode(bytes);
111
+ return JSON.parse(decoded);
112
+ } catch (e) {
113
+ throw new SDJWTException(errorMessage);
114
+ }
115
+ };
116
+
105
117
  // src/utils/disclosure.ts
106
118
  var Disclosure = class _Disclosure {
107
119
  constructor(data, _meta) {
@@ -128,7 +140,10 @@ var Disclosure = class _Disclosure {
128
140
  const { hasher, alg } = hash;
129
141
  const digest = yield hasher(s, alg);
130
142
  const digestStr = uint8ArrayToBase64Url(digest);
131
- const item = JSON.parse(base64urlDecode(s));
143
+ const item = decodeBase64urlJsonStrict(
144
+ s,
145
+ "Invalid disclosure data"
146
+ );
132
147
  return _Disclosure.fromArray(item, { digest: digestStr, encoded: s });
133
148
  });
134
149
  }
@@ -136,7 +151,10 @@ var Disclosure = class _Disclosure {
136
151
  const { hasher, alg } = hash;
137
152
  const digest = hasher(s, alg);
138
153
  const digestStr = uint8ArrayToBase64Url(digest);
139
- const item = JSON.parse(base64urlDecode(s));
154
+ const item = decodeBase64urlJsonStrict(
155
+ s,
156
+ "Invalid disclosure data"
157
+ );
140
158
  return _Disclosure.fromArray(item, { digest: digestStr, encoded: s });
141
159
  }
142
160
  static fromArray(item, _meta) {
@@ -178,8 +196,8 @@ var decodeJwt = (jwt) => {
178
196
  throw new SDJWTException("Invalid JWT as input");
179
197
  }
180
198
  return {
181
- header: JSON.parse(base64urlDecode(header)),
182
- payload: JSON.parse(base64urlDecode(payload)),
199
+ header: decodeBase64urlJsonStrict(header, "Invalid JWT as input"),
200
+ payload: decodeBase64urlJsonStrict(payload, "Invalid JWT as input"),
183
201
  signature
184
202
  };
185
203
  };
@@ -372,6 +390,11 @@ var getSDAlgAndPayload = (SdJwtPayload) => {
372
390
  if (typeof _sd_alg !== "string") {
373
391
  return { _sd_alg: "sha-256", payload };
374
392
  }
393
+ if (!IANA_HASH_ALGORITHMS.includes(
394
+ _sd_alg
395
+ )) {
396
+ throw new SDJWTException(`Invalid _sd_alg: ${_sd_alg}`);
397
+ }
375
398
  return { _sd_alg, payload };
376
399
  };
377
400
  var unpack = (SdJwtPayload, disclosures, hasher) => __async(null, null, function* () {
@@ -671,18 +694,13 @@ var KBJwt = class _KBJwt extends Jwt {
671
694
  !(this.payload.sd_hash || "_sd_hash" in this.payload && this.payload._sd_hash)) {
672
695
  throw new SDJWTException("Invalid Key Binding Jwt");
673
696
  }
674
- const data = this.getUnsignedToken();
675
- const verified = yield values.verifier(
676
- data,
677
- this.signature,
678
- values.payload
679
- );
680
- if (!verified) {
681
- throw new SDJWTException("Verify Error: Invalid JWT Signature");
682
- }
683
697
  if (this.payload.nonce !== values.nonce) {
684
698
  throw new SDJWTException("Verify Error: Invalid Nonce");
685
699
  }
700
+ yield this.verify(
701
+ (data, sig) => values.verifier(data, sig, values.payload),
702
+ values.options
703
+ );
686
704
  return { payload: this.payload, header: this.header };
687
705
  });
688
706
  }
@@ -1101,9 +1119,8 @@ var _SDJwtInstance = class _SDJwtInstance {
1101
1119
  if (!this.userConfig.signAlg) {
1102
1120
  throw new SDJWTException("sign alogrithm not specified");
1103
1121
  }
1104
- if (disclosureFrame) {
1105
- this.validateReservedFields(disclosureFrame);
1106
- }
1122
+ this.validateReservedFields(payload);
1123
+ this.validateDisclosureFrame(disclosureFrame);
1107
1124
  const hasher = this.userConfig.hasher;
1108
1125
  const hashAlg = (_a = this.userConfig.hashAlg) != null ? _a : _SDJwtInstance.DEFAULT_hashAlg;
1109
1126
  const { packedClaims, disclosures } = yield pack(
@@ -1131,11 +1148,30 @@ var _SDJwtInstance = class _SDJwtInstance {
1131
1148
  });
1132
1149
  }
1133
1150
  /**
1134
- * Validates if the disclosureFrame contains any reserved fields. If so it will throw an error.
1135
- * @param disclosureFrame
1151
+ * Validates if the payload contains any reserved claim names. If so it will throw an error.
1152
+ * @param payload
1136
1153
  * @returns
1137
1154
  */
1138
- validateReservedFields(_disclosureFrame) {
1155
+ validateReservedFields(payload) {
1156
+ const reservedFields = /* @__PURE__ */ new Set([SD_DIGEST, "_sd_alg", SD_DECOY]);
1157
+ const visit = (node) => {
1158
+ if (!node || typeof node !== "object") {
1159
+ return;
1160
+ }
1161
+ for (const [key, value] of Object.entries(
1162
+ node
1163
+ )) {
1164
+ if (reservedFields.has(key)) {
1165
+ throw new SDJWTException(
1166
+ `Reserved field name "${key}" is not allowed`
1167
+ );
1168
+ }
1169
+ visit(value);
1170
+ }
1171
+ };
1172
+ visit(payload);
1173
+ }
1174
+ validateDisclosureFrame(_disclosureFrame) {
1139
1175
  return;
1140
1176
  }
1141
1177
  present(encodedSDJwt, presentationFrame, options) {
@@ -1200,7 +1236,8 @@ var _SDJwtInstance = class _SDJwtInstance {
1200
1236
  const kb = yield sdjwt.kbJwt.verifyKB({
1201
1237
  verifier: this.userConfig.kbVerifier,
1202
1238
  payload,
1203
- nonce: options.keyBindingNonce
1239
+ nonce: options.keyBindingNonce,
1240
+ options
1204
1241
  });
1205
1242
  if (!kb) {
1206
1243
  throw new Error("signature is not valid");
@@ -1331,7 +1368,8 @@ var _SDJwtInstance = class _SDJwtInstance {
1331
1368
  const kbResult = yield sdjwt.kbJwt.verifyKB({
1332
1369
  verifier: this.userConfig.kbVerifier,
1333
1370
  payload,
1334
- nonce: options.keyBindingNonce
1371
+ nonce: options.keyBindingNonce,
1372
+ options
1335
1373
  });
1336
1374
  if (!kbResult) {
1337
1375
  addError(
@@ -1509,9 +1547,8 @@ var SDJwtGeneralJSONInstance = class {
1509
1547
  if (!this.userConfig.saltGenerator) {
1510
1548
  throw new SDJWTException("SaltGenerator not found");
1511
1549
  }
1512
- if (disclosureFrame) {
1513
- this.validateReservedFields(disclosureFrame);
1514
- }
1550
+ this.validateReservedFields(payload);
1551
+ this.validateDisclosureFrame(disclosureFrame);
1515
1552
  const hasher = this.userConfig.hasher;
1516
1553
  const hashAlg = (_a = this.userConfig.hashAlg) != null ? _a : SDJwtInstance.DEFAULT_hashAlg;
1517
1554
  const { packedClaims, disclosures } = yield pack(
@@ -1520,10 +1557,12 @@ var SDJwtGeneralJSONInstance = class {
1520
1557
  { hasher, alg: hashAlg },
1521
1558
  this.userConfig.saltGenerator
1522
1559
  );
1523
- const encodedDisclosures = disclosures.map((d) => d.encode());
1524
1560
  const encodedSDJwtPayload = this.encodeObj(__spreadProps(__spreadValues({}, packedClaims), {
1525
1561
  _sd_alg: disclosureFrame ? hashAlg : void 0
1526
1562
  }));
1563
+ const encodedDisclosures = disclosures.map(
1564
+ (disclosure) => disclosure.encode()
1565
+ );
1527
1566
  const signatures = yield Promise.all(
1528
1567
  options.sigs.map((s) => __async(this, null, function* () {
1529
1568
  const { signer, alg, kid, header } = s;
@@ -1534,7 +1573,6 @@ var SDJwtGeneralJSONInstance = class {
1534
1573
  );
1535
1574
  return {
1536
1575
  protected: encodedProtectedHeader,
1537
- kid,
1538
1576
  signature
1539
1577
  };
1540
1578
  }))
@@ -1548,11 +1586,30 @@ var SDJwtGeneralJSONInstance = class {
1548
1586
  });
1549
1587
  }
1550
1588
  /**
1551
- * Validates if the disclosureFrame contains any reserved fields. If so it will throw an error.
1552
- * @param disclosureFrame
1589
+ * Validates if the payload contains any reserved claim names. If so it will throw an error.
1590
+ * @param payload
1553
1591
  * @returns
1554
1592
  */
1555
- validateReservedFields(_disclosureFrame) {
1593
+ validateReservedFields(payload) {
1594
+ const reservedFields = /* @__PURE__ */ new Set([SD_DIGEST, "_sd_alg", SD_DECOY]);
1595
+ const visit = (node) => {
1596
+ if (!node || typeof node !== "object") {
1597
+ return;
1598
+ }
1599
+ for (const [key, value] of Object.entries(
1600
+ node
1601
+ )) {
1602
+ if (reservedFields.has(key)) {
1603
+ throw new SDJWTException(
1604
+ `Reserved field name "${key}" is not allowed`
1605
+ );
1606
+ }
1607
+ visit(value);
1608
+ }
1609
+ };
1610
+ visit(payload);
1611
+ }
1612
+ validateDisclosureFrame(_disclosureFrame) {
1556
1613
  return;
1557
1614
  }
1558
1615
  present(generalJSON, presentationFrame, options) {
@@ -1631,7 +1688,8 @@ var SDJwtGeneralJSONInstance = class {
1631
1688
  const kb = yield sdjwt.kbJwt.verifyKB({
1632
1689
  verifier: this.userConfig.kbVerifier,
1633
1690
  payload,
1634
- nonce: options.keyBindingNonce
1691
+ nonce: options.keyBindingNonce,
1692
+ options
1635
1693
  });
1636
1694
  if (!kb) {
1637
1695
  throw new Error("signature is not valid");
@@ -1684,7 +1742,7 @@ var SDJwtGeneralJSONInstance = class {
1684
1742
  `${encodedHeader}.${payload}`,
1685
1743
  signature
1686
1744
  );
1687
- const header = JSON.parse(base64urlDecode(encodedHeader));
1745
+ const header = decodeBase64urlJsonStrict(encodedHeader, "Invalid JWT");
1688
1746
  return { verified: verified2, header };
1689
1747
  }))
1690
1748
  );
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sd-jwt/core",
3
- "version": "0.19.1-next.9+d8ec21a",
3
+ "version": "0.20.1-next.0+af170ac",
4
4
  "description": "sd-jwt draft 7 implementation in typescript",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -58,5 +58,5 @@
58
58
  "esm"
59
59
  ]
60
60
  },
61
- "gitHead": "d8ec21aa144d1d3a0fb5eb9fe5c609696b2076aa"
61
+ "gitHead": "af170ace9b42984f8c6447caf23256fde6204b31"
62
62
  }