@sd-jwt/core 0.20.1 → 0.21.0-alpha-20260916100413

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.
Files changed (68) hide show
  1. package/LICENSE +2 -2
  2. package/README.md +82 -80
  3. package/dist/index.cjs +1526 -0
  4. package/dist/index.cjs.map +1 -0
  5. package/dist/index.d.cts +696 -0
  6. package/dist/index.d.mts +537 -527
  7. package/dist/index.mjs +1422 -1998
  8. package/dist/index.mjs.map +1 -0
  9. package/package.json +29 -49
  10. package/CHANGELOG.md +0 -39
  11. package/dist/index.d.ts +0 -686
  12. package/dist/index.js +0 -2100
  13. package/src/decode/decode.ts +0 -407
  14. package/src/decode/index.ts +0 -1
  15. package/src/decoy.ts +0 -15
  16. package/src/flattenJSON.ts +0 -99
  17. package/src/generalJSON.ts +0 -157
  18. package/src/index.ts +0 -1000
  19. package/src/jwt.ts +0 -286
  20. package/src/kbjwt.ts +0 -101
  21. package/src/present/index.ts +0 -1
  22. package/src/present/present.ts +0 -216
  23. package/src/sdjwt.ts +0 -384
  24. package/src/test/decode/decode.spec.ts +0 -197
  25. package/src/test/decoy.spec.ts +0 -30
  26. package/src/test/flattenJSON.spec.ts +0 -122
  27. package/src/test/generalJSON.spec.ts +0 -198
  28. package/src/test/index.spec.ts +0 -986
  29. package/src/test/jwt.spec.ts +0 -301
  30. package/src/test/kbjwt.spec.ts +0 -555
  31. package/src/test/pass.spec.ts +0 -7
  32. package/src/test/present/present.spec.ts +0 -305
  33. package/src/test/sdjwt.spec.ts +0 -384
  34. package/src/test/types/type.spec.ts +0 -88
  35. package/src/test/utils/base64url.spec.ts +0 -33
  36. package/src/test/utils/disclosure.spec.ts +0 -170
  37. package/src/test/utils/error.spec.ts +0 -15
  38. package/src/types/index.ts +0 -2
  39. package/src/types/type.ts +0 -270
  40. package/src/types/verification-error.ts +0 -55
  41. package/src/utils/base64url.ts +0 -6
  42. package/src/utils/disclosure.ts +0 -121
  43. package/src/utils/error.ts +0 -25
  44. package/src/utils/index.ts +0 -3
  45. package/src/utils/strict-json.ts +0 -17
  46. package/test/app-e2e.spec.ts +0 -292
  47. package/test/array_data_types.json +0 -31
  48. package/test/array_full_sd.json +0 -21
  49. package/test/array_in_sd.json +0 -13
  50. package/test/array_nested_in_plain.json +0 -29
  51. package/test/array_none_disclosed.json +0 -17
  52. package/test/array_of_nulls.json +0 -15
  53. package/test/array_of_objects.json +0 -65
  54. package/test/array_of_scalars.json +0 -19
  55. package/test/array_recursive_sd.json +0 -35
  56. package/test/array_recursive_sd_some_disclosed.json +0 -63
  57. package/test/complex.json +0 -43
  58. package/test/header_mod.json +0 -48
  59. package/test/json_serialization.json +0 -48
  60. package/test/key_binding.json +0 -48
  61. package/test/no_sd.json +0 -36
  62. package/test/object_data_types.json +0 -62
  63. package/test/recursions.json +0 -117
  64. package/test/rfc9901-audit-fixes.spec.ts +0 -252
  65. package/test/rfc9901-validation.spec.ts +0 -150
  66. package/test/tsconfig.json +0 -4
  67. package/tsconfig.json +0 -7
  68. package/vitest.config.mts +0 -4
package/dist/index.cjs ADDED
@@ -0,0 +1,1526 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ let _owf_identity_common = require("@owf/identity-common");
3
+ //#region src/types/type.ts
4
+ const SD_SEPARATOR = "~";
5
+ const SD_LIST_KEY = "...";
6
+ const SD_DIGEST = "_sd";
7
+ const SD_DECOY = "_sd_decoy";
8
+ const KB_JWT_TYP = "kb+jwt";
9
+ const encodePathSegment = (segment) => segment.replace(/~/g, "~0").replace(/\./g, "~1");
10
+ const encodePath = (segments) => segments.map(encodePathSegment).join(".");
11
+ const IANA_HASH_ALGORITHMS = [
12
+ "sha-256",
13
+ "sha-256-128",
14
+ "sha-256-120",
15
+ "sha-256-96",
16
+ "sha-256-64",
17
+ "sha-256-32",
18
+ "sha-384",
19
+ "sha-512",
20
+ "sha3-224",
21
+ "sha3-256",
22
+ "sha3-384",
23
+ "sha3-512",
24
+ "blake2s-256",
25
+ "blake2b-256",
26
+ "blake2b-512",
27
+ "k12-256",
28
+ "k12-512"
29
+ ];
30
+ const DEFAULT_SECURE_HASH_ALGORITHMS = [
31
+ "sha-256",
32
+ "sha-384",
33
+ "sha-512",
34
+ "sha3-256",
35
+ "sha3-384",
36
+ "sha3-512",
37
+ "blake2s-256",
38
+ "blake2b-256",
39
+ "blake2b-512",
40
+ "k12-256",
41
+ "k12-512"
42
+ ];
43
+ //#endregion
44
+ //#region src/utils/error.ts
45
+ var SDJWTException = class SDJWTException extends Error {
46
+ constructor(message, details) {
47
+ super(message);
48
+ Object.setPrototypeOf(this, SDJWTException.prototype);
49
+ this.name = "SDJWTException";
50
+ this.details = details;
51
+ }
52
+ getFullMessage() {
53
+ return `${this.name}: ${this.message} ${this.details ? `- ${JSON.stringify(this.details)}` : ""}`;
54
+ }
55
+ };
56
+ /**
57
+ * Narrows an unknown caught value to an Error instance.
58
+ */
59
+ function ensureError(value) {
60
+ if (value instanceof Error) return value;
61
+ if (typeof value === "string") return new Error(value);
62
+ return new Error(String(value));
63
+ }
64
+ //#endregion
65
+ //#region src/utils/strict-json.ts
66
+ /**
67
+ * Decode base64url encoded JSON with {@link base64urlDecodeJson}, rethrowing failures as an
68
+ * `SDJWTException` with the given message.
69
+ */
70
+ const decodeBase64urlJsonStrict = (encoded, errorMessage) => {
71
+ try {
72
+ return (0, _owf_identity_common.base64urlDecodeJson)(encoded);
73
+ } catch {
74
+ throw new SDJWTException(errorMessage);
75
+ }
76
+ };
77
+ //#endregion
78
+ //#region src/utils/disclosure.ts
79
+ var Disclosure = class Disclosure {
80
+ constructor(data, _meta) {
81
+ if (!Array.isArray(data) || data.length !== 2 && data.length !== 3) throw new SDJWTException("Invalid disclosure data");
82
+ if (typeof data[0] !== "string") throw new SDJWTException("Invalid disclosure salt");
83
+ this._digest = _meta?.digest;
84
+ this._encoded = _meta?.encoded;
85
+ if (data.length === 2) {
86
+ this.salt = data[0];
87
+ this.value = data[1];
88
+ return;
89
+ }
90
+ if (data.length === 3) {
91
+ if (typeof data[1] !== "string") throw new SDJWTException("Invalid disclosure claim name");
92
+ if (data[1] === "_sd" || data[1] === "...") throw new SDJWTException(`Reserved disclosure claim name "${data[1]}" is not allowed`);
93
+ this.salt = data[0];
94
+ this.key = data[1];
95
+ this.value = data[2];
96
+ return;
97
+ }
98
+ }
99
+ static async fromEncode(s, hash) {
100
+ const { hasher, alg } = hash;
101
+ const digest = await hasher(s, alg);
102
+ const digestStr = (0, _owf_identity_common.uint8ArrayToBase64Url)(digest);
103
+ const item = decodeBase64urlJsonStrict(s, "Invalid disclosure data");
104
+ return Disclosure.fromArray(item, {
105
+ digest: digestStr,
106
+ encoded: s
107
+ });
108
+ }
109
+ static fromEncodeSync(s, hash) {
110
+ const { hasher, alg } = hash;
111
+ const digest = hasher(s, alg);
112
+ const digestStr = (0, _owf_identity_common.uint8ArrayToBase64Url)(digest);
113
+ const item = decodeBase64urlJsonStrict(s, "Invalid disclosure data");
114
+ return Disclosure.fromArray(item, {
115
+ digest: digestStr,
116
+ encoded: s
117
+ });
118
+ }
119
+ static fromArray(item, _meta) {
120
+ return new Disclosure(item, _meta);
121
+ }
122
+ encode() {
123
+ if (!this._encoded) this._encoded = (0, _owf_identity_common.base64urlEncode)(JSON.stringify(this.decode()));
124
+ return this._encoded;
125
+ }
126
+ decode() {
127
+ return this.key ? [
128
+ this.salt,
129
+ this.key,
130
+ this.value
131
+ ] : [this.salt, this.value];
132
+ }
133
+ async digest(hash) {
134
+ const { hasher, alg } = hash;
135
+ if (!this._digest) {
136
+ const hash = await hasher(this.encode(), alg);
137
+ this._digest = (0, _owf_identity_common.uint8ArrayToBase64Url)(hash);
138
+ }
139
+ return this._digest;
140
+ }
141
+ digestSync(hash) {
142
+ const { hasher, alg } = hash;
143
+ if (!this._digest) {
144
+ const hash = hasher(this.encode(), alg);
145
+ this._digest = (0, _owf_identity_common.uint8ArrayToBase64Url)(hash);
146
+ }
147
+ return this._digest;
148
+ }
149
+ };
150
+ //#endregion
151
+ //#region src/decode/decode.ts
152
+ /**
153
+ * Decode a JWT with `decodeJwt` from `@owf/identity-common`, rethrowing failures as an `SDJWTException`.
154
+ */
155
+ const decodeJwt = (jwt) => {
156
+ try {
157
+ return (0, _owf_identity_common.decodeJwt)(jwt);
158
+ } catch {
159
+ throw new SDJWTException("Invalid JWT as input");
160
+ }
161
+ };
162
+ const splitSdJwt = (sdjwt) => {
163
+ const [encodedJwt, ...encodedDisclosures] = sdjwt.split("~");
164
+ if (encodedDisclosures.length === 0) throw new SDJWTException("Invalid SD-JWT: missing SD-JWT separator");
165
+ return {
166
+ jwt: encodedJwt,
167
+ disclosures: encodedDisclosures,
168
+ kbJwt: encodedDisclosures.pop() || void 0
169
+ };
170
+ };
171
+ const decodeSdJwt = async (sdjwt, hasher) => {
172
+ const [encodedJwt, ...encodedDisclosures] = sdjwt.split("~");
173
+ const jwt = decodeJwt(encodedJwt);
174
+ if (encodedDisclosures.length === 0) throw new SDJWTException("Invalid SD-JWT: missing SD-JWT separator");
175
+ const encodedKeyBindingJwt = encodedDisclosures.pop();
176
+ const kbJwt = encodedKeyBindingJwt ? decodeJwt(encodedKeyBindingJwt) : void 0;
177
+ const { _sd_alg } = getSDAlgAndPayload(jwt.payload);
178
+ return {
179
+ jwt,
180
+ disclosures: await Promise.all(encodedDisclosures.map((ed) => Disclosure.fromEncode(ed, {
181
+ alg: _sd_alg,
182
+ hasher
183
+ }))),
184
+ kbJwt
185
+ };
186
+ };
187
+ const decodeSdJwtSync = (sdjwt, hasher) => {
188
+ const [encodedJwt, ...encodedDisclosures] = sdjwt.split("~");
189
+ const jwt = decodeJwt(encodedJwt);
190
+ if (encodedDisclosures.length === 0) throw new SDJWTException("Invalid SD-JWT: missing SD-JWT separator");
191
+ const encodedKeyBindingJwt = encodedDisclosures.pop();
192
+ const kbJwt = encodedKeyBindingJwt ? decodeJwt(encodedKeyBindingJwt) : void 0;
193
+ const { _sd_alg } = getSDAlgAndPayload(jwt.payload);
194
+ return {
195
+ jwt,
196
+ disclosures: encodedDisclosures.map((ed) => Disclosure.fromEncodeSync(ed, {
197
+ alg: _sd_alg,
198
+ hasher
199
+ })),
200
+ kbJwt
201
+ };
202
+ };
203
+ const getClaims = async (rawPayload, disclosures, hasher) => {
204
+ const { unpackedObj } = await unpack(rawPayload, disclosures, hasher);
205
+ return unpackedObj;
206
+ };
207
+ const getClaimsSync = (rawPayload, disclosures, hasher) => {
208
+ const { unpackedObj } = unpackSync(rawPayload, disclosures, hasher);
209
+ return unpackedObj;
210
+ };
211
+ const isRecord = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
212
+ const unpackArray = (arr, map, prefix = "", seenDigests) => {
213
+ const keys = {};
214
+ const unpackedArray = [];
215
+ arr.forEach((item, idx) => {
216
+ if (isRecord(item)) {
217
+ const hash = item["..."];
218
+ if ("..." in item) {
219
+ if (Object.keys(item).length !== 1 || typeof hash !== "string") throw new SDJWTException("Invalid array disclosure placeholder");
220
+ if (seenDigests) {
221
+ if (seenDigests.has(hash)) throw new SDJWTException("Duplicate digest found in SD-JWT payload");
222
+ seenDigests.add(hash);
223
+ }
224
+ const disclosed = map[hash];
225
+ if (disclosed) {
226
+ if (typeof disclosed.key === "string") throw new SDJWTException("Object-property disclosure cannot be used as an array element");
227
+ const presentKey = prefix ? `${prefix}.${idx}` : `${idx}`;
228
+ keys[presentKey] = hash;
229
+ const { unpackedObj, disclosureKeymap: disclosureKeys } = unpackObjInternal(disclosed.value, map, presentKey, seenDigests);
230
+ unpackedArray.push(unpackedObj);
231
+ Object.assign(keys, disclosureKeys);
232
+ }
233
+ } else {
234
+ const newKey = prefix ? `${prefix}.${idx}` : `${idx}`;
235
+ const { unpackedObj, disclosureKeymap: disclosureKeys } = unpackObjInternal(item, map, newKey, seenDigests);
236
+ unpackedArray.push(unpackedObj);
237
+ Object.assign(keys, disclosureKeys);
238
+ }
239
+ } else if (Array.isArray(item)) {
240
+ const newKey = prefix ? `${prefix}.${idx}` : `${idx}`;
241
+ const { unpackedObj, disclosureKeymap: disclosureKeys } = unpackObjInternal(item, map, newKey, seenDigests);
242
+ unpackedArray.push(unpackedObj);
243
+ Object.assign(keys, disclosureKeys);
244
+ } else unpackedArray.push(item);
245
+ });
246
+ return {
247
+ unpackedObj: unpackedArray,
248
+ disclosureKeymap: keys
249
+ };
250
+ };
251
+ const unpackObj = (obj, map) => {
252
+ const copiedObj = JSON.parse(JSON.stringify(obj));
253
+ const seenDigests = /* @__PURE__ */ new Set();
254
+ const result = unpackObjInternal(copiedObj, map, "", seenDigests);
255
+ if (Object.keys(map).filter((d) => !seenDigests.has(d)).length > 0) throw new SDJWTException("Unreferenced disclosure(s) detected in SD-JWT");
256
+ return result;
257
+ };
258
+ const unpackObjInternal = (obj, map, prefix = "", seenDigests) => {
259
+ const keys = {};
260
+ if (typeof obj === "object" && obj !== null) {
261
+ if (Array.isArray(obj)) return unpackArray(obj, map, prefix, seenDigests);
262
+ const record = obj;
263
+ for (const key in record) {
264
+ if (prefix && key === "_sd_alg") throw new SDJWTException("Nested _sd_alg is not allowed");
265
+ if (key !== "_sd" && key !== "..." && typeof record[key] === "object") {
266
+ const escapedKey = encodePathSegment(key);
267
+ const newKey = prefix ? `${prefix}.${escapedKey}` : escapedKey;
268
+ const { unpackedObj, disclosureKeymap: disclosureKeys } = unpackObjInternal(record[key], map, newKey, seenDigests);
269
+ record[key] = unpackedObj;
270
+ Object.assign(keys, disclosureKeys);
271
+ }
272
+ }
273
+ const { _sd, ...payload } = record;
274
+ const claims = {};
275
+ if (_sd !== void 0) {
276
+ if (!Array.isArray(_sd) || !_sd.every((hash) => typeof hash === "string")) throw new SDJWTException("Invalid _sd claim: expected array of strings");
277
+ for (const hash of _sd) {
278
+ if (seenDigests) {
279
+ if (seenDigests.has(hash)) throw new SDJWTException("Duplicate digest found in SD-JWT payload");
280
+ seenDigests.add(hash);
281
+ }
282
+ const disclosed = map[hash];
283
+ if (disclosed) {
284
+ if (typeof disclosed.key !== "string") throw new SDJWTException("Array disclosure cannot be used as an object property");
285
+ if (disclosed.key in payload) throw new SDJWTException(`Disclosed claim name "${disclosed.key}" conflicts with existing payload key`);
286
+ if (disclosed.key in claims) throw new SDJWTException(`Disclosed claim name "${disclosed.key}" conflicts with another disclosure`);
287
+ const escapedKey = encodePathSegment(disclosed.key);
288
+ const presentKey = prefix ? `${prefix}.${escapedKey}` : escapedKey;
289
+ keys[presentKey] = hash;
290
+ const { unpackedObj, disclosureKeymap: disclosureKeys } = unpackObjInternal(disclosed.value, map, presentKey, seenDigests);
291
+ claims[disclosed.key] = unpackedObj;
292
+ Object.assign(keys, disclosureKeys);
293
+ }
294
+ }
295
+ }
296
+ return {
297
+ unpackedObj: Object.assign(payload, claims),
298
+ disclosureKeymap: keys
299
+ };
300
+ }
301
+ return {
302
+ unpackedObj: obj,
303
+ disclosureKeymap: keys
304
+ };
305
+ };
306
+ const createHashMapping = async (disclosures, hash) => {
307
+ const map = {};
308
+ for (let i = 0; i < disclosures.length; i++) {
309
+ const disclosure = disclosures[i];
310
+ const digest = await disclosure.digest(hash);
311
+ if (digest in map) throw new SDJWTException("Duplicate disclosure digest detected");
312
+ map[digest] = disclosure;
313
+ }
314
+ return map;
315
+ };
316
+ const createHashMappingSync = (disclosures, hash) => {
317
+ const map = {};
318
+ for (let i = 0; i < disclosures.length; i++) {
319
+ const disclosure = disclosures[i];
320
+ const digest = disclosure.digestSync(hash);
321
+ if (digest in map) throw new SDJWTException("Duplicate disclosure digest detected");
322
+ map[digest] = disclosure;
323
+ }
324
+ return map;
325
+ };
326
+ const getSDAlgAndPayload = (SdJwtPayload, allowedAlgorithms = DEFAULT_SECURE_HASH_ALGORITHMS) => {
327
+ const { _sd_alg, ...payload } = SdJwtPayload;
328
+ if (_sd_alg === void 0) return {
329
+ _sd_alg: "sha-256",
330
+ payload
331
+ };
332
+ if (typeof _sd_alg !== "string") throw new SDJWTException("Invalid _sd_alg: expected string");
333
+ if (!IANA_HASH_ALGORITHMS.includes(_sd_alg)) throw new SDJWTException(`Invalid _sd_alg: ${_sd_alg}`);
334
+ if (!allowedAlgorithms.includes(_sd_alg)) throw new SDJWTException(`Disallowed _sd_alg: ${_sd_alg}`);
335
+ return {
336
+ _sd_alg,
337
+ payload
338
+ };
339
+ };
340
+ const unpack = async (SdJwtPayload, disclosures, hasher) => {
341
+ const { _sd_alg, payload } = getSDAlgAndPayload(SdJwtPayload);
342
+ const map = await createHashMapping(disclosures, {
343
+ hasher,
344
+ alg: _sd_alg
345
+ });
346
+ return unpackObj(payload, map);
347
+ };
348
+ const unpackSync = (SdJwtPayload, disclosures, hasher) => {
349
+ const { _sd_alg, payload } = getSDAlgAndPayload(SdJwtPayload);
350
+ const map = createHashMappingSync(disclosures, {
351
+ hasher,
352
+ alg: _sd_alg
353
+ });
354
+ return unpackObj(payload, map);
355
+ };
356
+ //#endregion
357
+ //#region src/flattenJSON.ts
358
+ var FlattenJSON = class FlattenJSON {
359
+ constructor(data) {
360
+ this.disclosures = data.disclosures;
361
+ this.kb_jwt = data.kb_jwt;
362
+ this.payload = data.jwtData.payload;
363
+ this.signature = data.jwtData.signature;
364
+ this.protected = data.jwtData.protected;
365
+ }
366
+ static fromEncode(encodedSdJwt) {
367
+ const { jwt, disclosures, kbJwt } = splitSdJwt(encodedSdJwt);
368
+ const { 0: protectedHeader, 1: payload, 2: signature } = jwt.split(".");
369
+ if (!protectedHeader || !payload || !signature) throw new SDJWTException("Invalid JWT");
370
+ return new FlattenJSON({
371
+ jwtData: {
372
+ protected: protectedHeader,
373
+ payload,
374
+ signature
375
+ },
376
+ disclosures,
377
+ kb_jwt: kbJwt
378
+ });
379
+ }
380
+ static fromSerialized(json) {
381
+ return new FlattenJSON({
382
+ jwtData: {
383
+ protected: json.protected,
384
+ payload: json.payload,
385
+ signature: json.signature
386
+ },
387
+ disclosures: json.header.disclosures,
388
+ kb_jwt: json.header.kb_jwt
389
+ });
390
+ }
391
+ toJson() {
392
+ return {
393
+ payload: this.payload,
394
+ signature: this.signature,
395
+ protected: this.protected,
396
+ header: {
397
+ disclosures: this.disclosures,
398
+ kb_jwt: this.kb_jwt
399
+ }
400
+ };
401
+ }
402
+ toEncoded() {
403
+ const data = [];
404
+ const jwt = `${this.protected}.${this.payload}.${this.signature}`;
405
+ data.push(jwt);
406
+ if (this.disclosures && this.disclosures.length > 0) {
407
+ const disclosures = this.disclosures.join("~");
408
+ data.push(disclosures);
409
+ }
410
+ const kb_jwt = this.kb_jwt ?? "";
411
+ data.push(kb_jwt);
412
+ return data.join("~");
413
+ }
414
+ };
415
+ //#endregion
416
+ //#region src/generalJSON.ts
417
+ var GeneralJSON = class GeneralJSON {
418
+ constructor(data) {
419
+ this.payload = data.payload;
420
+ this.disclosures = data.disclosures;
421
+ this.kb_jwt = data.kb_jwt;
422
+ this.signatures = data.signatures;
423
+ }
424
+ static fromEncode(encodedSdJwt) {
425
+ const { jwt, disclosures, kbJwt } = splitSdJwt(encodedSdJwt);
426
+ const { 0: protectedHeader, 1: payload, 2: signature } = jwt.split(".");
427
+ if (!protectedHeader || !payload || !signature) throw new SDJWTException("Invalid JWT");
428
+ return new GeneralJSON({
429
+ payload,
430
+ disclosures,
431
+ kb_jwt: kbJwt,
432
+ signatures: [{
433
+ protected: protectedHeader,
434
+ signature
435
+ }]
436
+ });
437
+ }
438
+ static fromSerialized(json) {
439
+ if (!json.signatures[0]) throw new SDJWTException("Invalid JSON");
440
+ for (let index = 1; index < json.signatures.length; index++) {
441
+ const header = json.signatures[index].header;
442
+ if (header && ("disclosures" in header || "kb_jwt" in header)) throw new SDJWTException("disclosures and kb_jwt MUST only appear in the first unprotected header");
443
+ }
444
+ const disclosures = json.signatures[0].header?.disclosures ?? [];
445
+ const kb_jwt = json.signatures[0].header?.kb_jwt;
446
+ return new GeneralJSON({
447
+ payload: json.payload,
448
+ disclosures,
449
+ kb_jwt,
450
+ signatures: json.signatures.map((s) => {
451
+ return {
452
+ protected: s.protected,
453
+ signature: s.signature,
454
+ kid: s.header?.kid
455
+ };
456
+ })
457
+ });
458
+ }
459
+ toJson() {
460
+ return {
461
+ payload: this.payload,
462
+ signatures: this.signatures.map((s, i) => {
463
+ if (i !== 0) return {
464
+ header: { kid: s.kid },
465
+ protected: s.protected,
466
+ signature: s.signature
467
+ };
468
+ return {
469
+ header: {
470
+ disclosures: this.disclosures,
471
+ kid: s.kid,
472
+ kb_jwt: this.kb_jwt
473
+ },
474
+ protected: s.protected,
475
+ signature: s.signature
476
+ };
477
+ })
478
+ };
479
+ }
480
+ toEncoded(index) {
481
+ if (index < 0 || index >= this.signatures.length) throw new SDJWTException("Index out of bounds");
482
+ const data = [];
483
+ const { protected: protectedHeader, signature } = this.signatures[index];
484
+ const jwt = `${protectedHeader}.${this.payload}.${signature}`;
485
+ data.push(jwt);
486
+ if (this.disclosures && this.disclosures.length > 0) {
487
+ const disclosures = this.disclosures.join("~");
488
+ data.push(disclosures);
489
+ }
490
+ const kb = this.kb_jwt ?? "";
491
+ data.push(kb);
492
+ return data.join("~");
493
+ }
494
+ async addSignature(protectedHeader, signer, kid) {
495
+ const header = (0, _owf_identity_common.base64urlEncode)(JSON.stringify(protectedHeader));
496
+ const signature = await signer(`${header}.${this.payload}`);
497
+ this.signatures.push({
498
+ protected: header,
499
+ signature,
500
+ kid
501
+ });
502
+ }
503
+ };
504
+ //#endregion
505
+ //#region src/jwt.ts
506
+ const isStringArray = (value) => Array.isArray(value) && value.every((item) => typeof item === "string");
507
+ const validateNumericDate = (payload, claim) => {
508
+ const value = payload[claim];
509
+ if (value === void 0) return void 0;
510
+ if (typeof value !== "number" || !Number.isFinite(value)) throw new SDJWTException(`Verify Error: JWT ${claim} must be a number`);
511
+ return value;
512
+ };
513
+ const getAudiences = (audience) => {
514
+ if (typeof audience === "string") return [audience];
515
+ if (isStringArray(audience)) return audience;
516
+ };
517
+ const validateAudience = (payload, expectedAudience) => {
518
+ if (expectedAudience === void 0) return;
519
+ const expectedAudiences = Array.isArray(expectedAudience) ? expectedAudience : [expectedAudience];
520
+ const audiences = getAudiences(payload.aud);
521
+ if (!audiences || !expectedAudiences.some((expected) => audiences.includes(expected))) throw new SDJWTException("Verify Error: Invalid audience");
522
+ };
523
+ const validateJwtPayload = (payload, options) => {
524
+ if (!payload) throw new SDJWTException("Verify Error: JWT payload is missing");
525
+ const skew = options?.skewSeconds ? options.skewSeconds : 0;
526
+ const currentDate = options?.currentDate ?? (0, _owf_identity_common.nowInSeconds)();
527
+ const iat = validateNumericDate(payload, "iat");
528
+ const nbf = validateNumericDate(payload, "nbf");
529
+ const exp = validateNumericDate(payload, "exp");
530
+ if (iat !== void 0 && iat - skew > currentDate) throw new SDJWTException("Verify Error: JWT is not yet valid");
531
+ if (nbf !== void 0 && nbf - skew > currentDate) throw new SDJWTException("Verify Error: JWT is not yet valid");
532
+ if (exp !== void 0 && exp + skew <= currentDate) throw new SDJWTException("Verify Error: JWT is expired");
533
+ validateAudience(payload, options?.expectedAudience);
534
+ };
535
+ var Jwt = class Jwt {
536
+ constructor(data) {
537
+ this.header = data?.header;
538
+ this.payload = data?.payload;
539
+ this.signature = data?.signature;
540
+ this.encoded = data?.encoded;
541
+ }
542
+ static decodeJWT(jwt) {
543
+ return decodeJwt(jwt);
544
+ }
545
+ static fromEncode(encodedJwt) {
546
+ const { header, payload, signature } = Jwt.decodeJWT(encodedJwt);
547
+ return new Jwt({
548
+ header,
549
+ payload,
550
+ signature,
551
+ encoded: encodedJwt
552
+ });
553
+ }
554
+ setHeader(header) {
555
+ this.header = header;
556
+ this.encoded = void 0;
557
+ return this;
558
+ }
559
+ setPayload(payload) {
560
+ this.payload = payload;
561
+ this.encoded = void 0;
562
+ return this;
563
+ }
564
+ getUnsignedToken() {
565
+ if (!this.header || !this.payload) throw new SDJWTException("Serialize Error: Invalid JWT");
566
+ if (this.encoded) {
567
+ const parts = this.encoded.split(".");
568
+ if (parts.length !== 3) throw new SDJWTException(`Invalid JWT format: ${this.encoded}`);
569
+ return parts.slice(0, 2).join(".");
570
+ }
571
+ return `${(0, _owf_identity_common.base64urlEncode)(JSON.stringify(this.header))}.${(0, _owf_identity_common.base64urlEncode)(JSON.stringify(this.payload))}`;
572
+ }
573
+ async sign(signer) {
574
+ if (!this.header || this.header.alg === "none") throw new SDJWTException("Sign Error: alg \"none\" is not allowed");
575
+ const data = this.getUnsignedToken();
576
+ this.signature = await signer(data);
577
+ return this.encodeJwt();
578
+ }
579
+ encodeJwt() {
580
+ if (this.encoded) return this.encoded;
581
+ if (!this.header || !this.payload || !this.signature) throw new SDJWTException("Serialize Error: Invalid JWT");
582
+ const compact = `${(0, _owf_identity_common.base64urlEncode)(JSON.stringify(this.header))}.${(0, _owf_identity_common.base64urlEncode)(JSON.stringify(this.payload))}.${this.signature}`;
583
+ this.encoded = compact;
584
+ return compact;
585
+ }
586
+ /**
587
+ * Verify the JWT using the provided verifier function.
588
+ * It checks the signature and validates the iat, nbf, and exp claims if they are present.
589
+ * @param verifier
590
+ * @param options - Options for verification, such as current date and skew seconds
591
+ * @returns
592
+ */
593
+ async verify(verifier, options) {
594
+ const alg = this.header?.alg;
595
+ if (typeof alg !== "string" || alg === "none") throw new SDJWTException("Verify Error: alg \"none\" is not allowed");
596
+ if (options?.allowedIssuerAlgorithms && !options.allowedIssuerAlgorithms.includes(alg)) throw new SDJWTException(`Verify Error: Disallowed alg ${alg}`);
597
+ if (!options?.skipJwtClaimValidation) validateJwtPayload(this.payload, options);
598
+ if (!this.signature) throw new SDJWTException("Verify Error: no signature in JWT");
599
+ if (!await verifier(this.getUnsignedToken(), this.signature, options)) throw new SDJWTException("Verify Error: Invalid JWT Signature");
600
+ return {
601
+ payload: this.payload,
602
+ header: this.header
603
+ };
604
+ }
605
+ };
606
+ //#endregion
607
+ //#region src/kbjwt.ts
608
+ var KBJwt = class KBJwt extends Jwt {
609
+ async verifyKB(values) {
610
+ if (!this.header || !this.payload || !this.signature) throw new SDJWTException("Verify Error: Invalid JWT");
611
+ if (typeof this.header.alg !== "string" || this.header.alg === "none" || typeof this.header.typ !== "string" || this.header.typ !== "kb+jwt" || typeof this.payload.iat !== "number" || typeof this.payload.aud !== "string" || typeof this.payload.nonce !== "string" || typeof this.payload.sd_hash !== "string" || this.payload.sd_hash.length === 0) throw new SDJWTException("Invalid Key Binding Jwt");
612
+ if (this.payload.nonce !== values.nonce) throw new SDJWTException("Verify Error: Invalid Nonce");
613
+ if (values.options?.expectedKeyBindingAudience !== void 0) {
614
+ if (!(Array.isArray(values.options.expectedKeyBindingAudience) ? values.options.expectedKeyBindingAudience : [values.options.expectedKeyBindingAudience]).includes(this.payload.aud)) throw new SDJWTException("Verify Error: Invalid Key Binding audience");
615
+ }
616
+ if (values.options?.keyBindingMaxAgeSeconds !== void 0) {
617
+ const currentDate = values.options.currentDate ?? (0, _owf_identity_common.nowInSeconds)();
618
+ const skew = values.options.skewSeconds ?? 0;
619
+ if (this.payload.iat + values.options.keyBindingMaxAgeSeconds + skew < currentDate) throw new SDJWTException("Verify Error: Key Binding JWT is too old");
620
+ }
621
+ await this.verify((data, sig) => values.verifier(data, sig, values.payload), values.options);
622
+ return {
623
+ payload: this.payload,
624
+ header: this.header
625
+ };
626
+ }
627
+ static fromKBEncode(encodedJwt) {
628
+ const { header, payload, signature } = Jwt.decodeJWT(encodedJwt);
629
+ return new KBJwt({
630
+ header,
631
+ payload,
632
+ signature,
633
+ encoded: encodedJwt
634
+ });
635
+ }
636
+ };
637
+ //#endregion
638
+ //#region src/decoy.ts
639
+ const createDecoy = async (hash, saltGenerator) => {
640
+ const { hasher, alg } = hash;
641
+ const decoy = await hasher(await saltGenerator(16), alg);
642
+ return (0, _owf_identity_common.uint8ArrayToBase64Url)(decoy);
643
+ };
644
+ //#endregion
645
+ //#region src/present/present.ts
646
+ const presentableKeys = async (rawPayload, disclosures, hasher) => {
647
+ const { disclosureKeymap } = await unpack(rawPayload, disclosures, hasher);
648
+ return Object.keys(disclosureKeymap).sort();
649
+ };
650
+ const presentableKeysSync = (rawPayload, disclosures, hasher) => {
651
+ const { disclosureKeymap } = unpackSync(rawPayload, disclosures, hasher);
652
+ return Object.keys(disclosureKeymap).sort();
653
+ };
654
+ const present = async (sdJwt, presentFrame, hasher) => {
655
+ const { jwt, kbJwt } = splitSdJwt(sdJwt);
656
+ const { jwt: { payload }, disclosures } = await decodeSdJwt(sdJwt, hasher);
657
+ const { _sd_alg: alg } = getSDAlgAndPayload(payload);
658
+ const hash = {
659
+ alg,
660
+ hasher
661
+ };
662
+ const keys = transformPresentationFrame(presentFrame);
663
+ const hashmap = await createHashMapping(disclosures, hash);
664
+ const { disclosureKeymap } = await unpack(payload, disclosures, hasher);
665
+ return [
666
+ jwt,
667
+ ...keys.map((k) => hashmap[disclosureKeymap[k]]).filter((d) => d !== void 0).map((d) => d.encode()),
668
+ kbJwt ?? ""
669
+ ].join("~");
670
+ };
671
+ const presentSync = (sdJwt, presentFrame, hasher) => {
672
+ const { jwt, kbJwt } = splitSdJwt(sdJwt);
673
+ const { jwt: { payload }, disclosures } = decodeSdJwtSync(sdJwt, hasher);
674
+ const { _sd_alg: alg } = getSDAlgAndPayload(payload);
675
+ const hash = {
676
+ alg,
677
+ hasher
678
+ };
679
+ const keys = transformPresentationFrame(presentFrame);
680
+ const hashmap = createHashMappingSync(disclosures, hash);
681
+ const { disclosureKeymap } = unpackSync(payload, disclosures, hasher);
682
+ return [
683
+ jwt,
684
+ ...keys.map((k) => hashmap[disclosureKeymap[k]]).filter((d) => d !== void 0).map((d) => d.encode()),
685
+ kbJwt ?? ""
686
+ ].join("~");
687
+ };
688
+ /**
689
+ * Transform the object keys into an array of strings. We are not sorting the array in any way.
690
+ * @param obj The object to transform
691
+ * @param prefix The prefix to add to the keys
692
+ * @returns
693
+ */
694
+ const transformPresentationFrame = (obj, prefix = []) => {
695
+ return Object.entries(obj).reduce((acc, [key, value]) => {
696
+ const newPrefix = [...prefix, key];
697
+ const encodedPrefix = encodePath(newPrefix);
698
+ if (typeof value === "boolean") {
699
+ if (value) acc.push(encodedPrefix);
700
+ } else if (typeof value === "object" && value !== null) acc.push(encodedPrefix, ...transformPresentationFrame(value, newPrefix));
701
+ return acc;
702
+ }, []);
703
+ };
704
+ const createHashMappingForSerializedDisclosure = (disclosures) => {
705
+ const map = {};
706
+ for (let i = 0; i < disclosures.length; i++) {
707
+ const { digest, encoded, key, salt, value } = disclosures[i];
708
+ map[digest] = Disclosure.fromArray(key ? [
709
+ salt,
710
+ key,
711
+ value
712
+ ] : [salt, value], {
713
+ digest,
714
+ encoded
715
+ });
716
+ }
717
+ return map;
718
+ };
719
+ /**
720
+ * This function selects the serialized disclosures from the payload
721
+ * and array of serialized disclosure based on the presentation frame.
722
+ * If you want to know what is serialized disclosures, check type SerializedDisclosure.
723
+ * @param payload: Record<string, unknown>
724
+ * @param disclosures: SerializedDisclosure[]
725
+ * @param presentationFrame: PresentationFrame<T>
726
+ */
727
+ const selectDisclosures = (payload, disclosures, presentationFrame) => {
728
+ if (disclosures.length === 0) return [];
729
+ const hashmap = createHashMappingForSerializedDisclosure(disclosures);
730
+ const { disclosureKeymap } = unpackObj(payload, hashmap);
731
+ return transformPresentationFrame(presentationFrame).map((k) => hashmap[disclosureKeymap[k]]).filter((d) => d !== void 0).map((d) => {
732
+ const { salt, key, value, _digest } = d;
733
+ if (!_digest) throw new SDJWTException("Implementation error: _digest is not defined");
734
+ return {
735
+ digest: _digest,
736
+ encoded: d.encode(),
737
+ salt,
738
+ key,
739
+ value
740
+ };
741
+ });
742
+ };
743
+ //#endregion
744
+ //#region src/sdjwt.ts
745
+ const createDisclosureSalt = async (saltGenerator, seenSalts) => {
746
+ const salt = await saltGenerator(16);
747
+ if (typeof salt !== "string") throw new SDJWTException("SaltGenerator must return a string");
748
+ if (seenSalts.has(salt)) throw new SDJWTException("Duplicate disclosure salt detected");
749
+ seenSalts.add(salt);
750
+ return salt;
751
+ };
752
+ const addDisclosureDigest = (digest, seenDigests) => {
753
+ if (seenDigests.has(digest)) throw new SDJWTException("Duplicate disclosure digest detected");
754
+ seenDigests.add(digest);
755
+ };
756
+ var SDJwt = class SDJwt {
757
+ constructor(data) {
758
+ this.jwt = data?.jwt;
759
+ this.disclosures = data?.disclosures;
760
+ this.kbJwt = data?.kbJwt;
761
+ }
762
+ static async decodeSDJwt(sdjwt, hasher) {
763
+ const [encodedJwt, ...encodedDisclosures] = sdjwt.split("~");
764
+ if (encodedDisclosures.length === 0) throw new SDJWTException("Invalid SD-JWT: missing SD-JWT separator");
765
+ const jwt = Jwt.fromEncode(encodedJwt);
766
+ if (!jwt.payload) throw new Error("Payload is undefined on the JWT. Invalid state reached");
767
+ const encodedKeyBindingJwt = encodedDisclosures.pop();
768
+ const kbJwt = encodedKeyBindingJwt ? KBJwt.fromKBEncode(encodedKeyBindingJwt) : void 0;
769
+ const { _sd_alg } = getSDAlgAndPayload(jwt.payload);
770
+ return {
771
+ jwt,
772
+ disclosures: await Promise.all(encodedDisclosures.map((ed) => Disclosure.fromEncode(ed, {
773
+ alg: _sd_alg,
774
+ hasher
775
+ }))),
776
+ kbJwt
777
+ };
778
+ }
779
+ static async extractJwt(encodedSdJwt) {
780
+ const [encodedJwt, ..._encodedDisclosures] = encodedSdJwt.split("~");
781
+ return Jwt.fromEncode(encodedJwt);
782
+ }
783
+ static async fromEncode(encodedSdJwt, hasher) {
784
+ const { jwt, disclosures, kbJwt } = await SDJwt.decodeSDJwt(encodedSdJwt, hasher);
785
+ return new SDJwt({
786
+ jwt,
787
+ disclosures,
788
+ kbJwt
789
+ });
790
+ }
791
+ async present(presentFrame, hasher) {
792
+ const disclosures = await this.getPresentDisclosures(presentFrame, hasher);
793
+ return new SDJwt({
794
+ jwt: this.jwt,
795
+ disclosures,
796
+ kbJwt: this.kbJwt
797
+ }).encodeSDJwt();
798
+ }
799
+ async getPresentDisclosures(presentFrame, hasher) {
800
+ if (!this.jwt?.payload || !this.disclosures) throw new SDJWTException("Invalid sd-jwt: jwt or disclosures is missing");
801
+ const { _sd_alg: alg } = getSDAlgAndPayload(this.jwt.payload);
802
+ const hash = {
803
+ alg,
804
+ hasher
805
+ };
806
+ const hashmap = await createHashMapping(this.disclosures, hash);
807
+ const { disclosureKeymap } = await unpack(this.jwt.payload, this.disclosures, hasher);
808
+ return (presentFrame ? transformPresentationFrame(presentFrame) : await this.presentableKeys(hasher)).map((k) => hashmap[disclosureKeymap[k]]).filter((d) => d !== void 0);
809
+ }
810
+ encodeSDJwt() {
811
+ const data = [];
812
+ if (!this.jwt) throw new SDJWTException("Invalid sd-jwt: jwt is missing");
813
+ const encodedJwt = this.jwt.encodeJwt();
814
+ data.push(encodedJwt);
815
+ if (this.disclosures && this.disclosures.length > 0) {
816
+ const encodeddisclosures = this.disclosures.map((dc) => dc.encode()).join("~");
817
+ data.push(encodeddisclosures);
818
+ }
819
+ data.push(this.kbJwt ? this.kbJwt.encodeJwt() : "");
820
+ return data.join("~");
821
+ }
822
+ async keys(hasher) {
823
+ return listKeys(await this.getClaims(hasher)).sort();
824
+ }
825
+ async presentableKeys(hasher) {
826
+ if (!this.jwt?.payload || !this.disclosures) throw new SDJWTException("Invalid sd-jwt: jwt or disclosures is missing");
827
+ const { disclosureKeymap } = await unpack(this.jwt?.payload, this.disclosures, hasher);
828
+ return Object.keys(disclosureKeymap).sort();
829
+ }
830
+ async getClaims(hasher) {
831
+ if (!this.jwt?.payload || !this.disclosures) throw new SDJWTException("Invalid sd-jwt: jwt or disclosures is missing");
832
+ const { unpackedObj } = await unpack(this.jwt.payload, this.disclosures, hasher);
833
+ return unpackedObj;
834
+ }
835
+ };
836
+ const listKeys = (obj, prefix = "") => {
837
+ const keys = [];
838
+ for (const key in obj) {
839
+ if (obj[key] === void 0) continue;
840
+ const escapedKey = encodePathSegment(key);
841
+ const newKey = prefix ? `${prefix}.${escapedKey}` : escapedKey;
842
+ keys.push(newKey);
843
+ const value = obj[key];
844
+ if (value && typeof value === "object") keys.push(...listKeys(value, newKey));
845
+ }
846
+ return keys;
847
+ };
848
+ const pack = async (claims, disclosureFrame, hash, saltGenerator, seenSalts = /* @__PURE__ */ new Set(), seenDigests = /* @__PURE__ */ new Set()) => {
849
+ if (!disclosureFrame) return {
850
+ packedClaims: claims,
851
+ disclosures: []
852
+ };
853
+ const sd = disclosureFrame["_sd"] ?? [];
854
+ const decoyCount = disclosureFrame["_sd_decoy"] ?? 0;
855
+ if (Array.isArray(claims)) {
856
+ const packedClaims = [];
857
+ const disclosures = [];
858
+ const recursivePackedClaims = {};
859
+ for (const key in disclosureFrame) if (key !== "_sd") {
860
+ const idx = Number.parseInt(key, 10);
861
+ const packed = await pack(claims[idx], disclosureFrame[idx], hash, saltGenerator, seenSalts, seenDigests);
862
+ recursivePackedClaims[idx] = packed.packedClaims;
863
+ disclosures.push(...packed.disclosures);
864
+ }
865
+ for (let i = 0; i < claims.length; i++) {
866
+ const claim = recursivePackedClaims[i] ? recursivePackedClaims[i] : claims[i];
867
+ /** This part is set discloure for array items.
868
+ * The example of disclosureFrame of an Array is
869
+ *
870
+ * const claims = {
871
+ * array: ['a', 'b', 'c']
872
+ * }
873
+ *
874
+ * diclosureFrame: DisclosureFrame<typeof claims> = {
875
+ * array: {
876
+ * _sd: [0, 2]
877
+ * }
878
+ * }
879
+ *
880
+ * It means that we want to disclose the first and the third item of the array
881
+ *
882
+ * So If the index `i` is in the disclosure list(sd), then we create a disclosure for the claim
883
+ */
884
+ if (sd.includes(i)) {
885
+ const disclosure = new Disclosure([await createDisclosureSalt(saltGenerator, seenSalts), claim]);
886
+ const digest = await disclosure.digest(hash);
887
+ addDisclosureDigest(digest, seenDigests);
888
+ packedClaims.push({ ["..."]: digest });
889
+ disclosures.push(disclosure);
890
+ } else packedClaims.push(claim);
891
+ }
892
+ for (let j = 0; j < decoyCount; j++) {
893
+ const decoyDigest = await createDecoy(hash, saltGenerator);
894
+ addDisclosureDigest(decoyDigest, seenDigests);
895
+ packedClaims.push({ ["..."]: decoyDigest });
896
+ }
897
+ return {
898
+ packedClaims,
899
+ disclosures
900
+ };
901
+ }
902
+ const packedClaims = {};
903
+ const disclosures = [];
904
+ const recursivePackedClaims = {};
905
+ for (const key in disclosureFrame) if (key !== "_sd") {
906
+ const packed = await pack(claims[key], disclosureFrame[key], hash, saltGenerator, seenSalts, seenDigests);
907
+ recursivePackedClaims[key] = packed.packedClaims;
908
+ disclosures.push(...packed.disclosures);
909
+ }
910
+ const _sd = [];
911
+ for (const key in claims) {
912
+ const claim = recursivePackedClaims[key] ? recursivePackedClaims[key] : claims[key];
913
+ if (sd.includes(key)) {
914
+ const disclosure = new Disclosure([
915
+ await createDisclosureSalt(saltGenerator, seenSalts),
916
+ key,
917
+ claim
918
+ ]);
919
+ const digest = await disclosure.digest(hash);
920
+ addDisclosureDigest(digest, seenDigests);
921
+ _sd.push(digest);
922
+ disclosures.push(disclosure);
923
+ } else packedClaims[key] = claim;
924
+ }
925
+ for (let j = 0; j < decoyCount; j++) {
926
+ const decoyDigest = await createDecoy(hash, saltGenerator);
927
+ addDisclosureDigest(decoyDigest, seenDigests);
928
+ _sd.push(decoyDigest);
929
+ }
930
+ if (_sd.length > 0) packedClaims["_sd"] = _sd.sort();
931
+ return {
932
+ packedClaims,
933
+ disclosures
934
+ };
935
+ };
936
+ //#endregion
937
+ //#region src/index.ts
938
+ /**
939
+ * Internal utility function to validate that a payload does not contain reserved field names.
940
+ */
941
+ function validateReservedFieldsInternal(payload) {
942
+ const reservedFields = /* @__PURE__ */ new Set([
943
+ "_sd",
944
+ "_sd_alg",
945
+ SD_DECOY,
946
+ "..."
947
+ ]);
948
+ const visit = (node) => {
949
+ if (!node || typeof node !== "object") return;
950
+ for (const [key, value] of Object.entries(node)) {
951
+ if (reservedFields.has(key)) throw new SDJWTException(`Reserved field name "${key}" is not allowed`);
952
+ visit(value);
953
+ }
954
+ };
955
+ visit(payload);
956
+ }
957
+ var SDJwtInstance = class SDJwtInstance {
958
+ static {
959
+ this.DEFAULT_hashAlg = "sha-256";
960
+ }
961
+ constructor(userConfig) {
962
+ this.userConfig = {};
963
+ if (userConfig) {
964
+ if (userConfig.hashAlg && !IANA_HASH_ALGORITHMS.includes(userConfig.hashAlg)) throw new SDJWTException(`Invalid hash algorithm: ${userConfig.hashAlg}`);
965
+ const allowedDisclosureHashAlgorithms = userConfig.allowedDisclosureHashAlgorithms ?? DEFAULT_SECURE_HASH_ALGORITHMS;
966
+ if (userConfig.hashAlg && !allowedDisclosureHashAlgorithms.includes(userConfig.hashAlg)) throw new SDJWTException(`Disallowed hash algorithm: ${userConfig.hashAlg}`);
967
+ this.userConfig = userConfig;
968
+ }
969
+ }
970
+ async createKBJwt(options, sdHash) {
971
+ if (!this.userConfig.kbSigner) throw new SDJWTException("Key Binding Signer not found");
972
+ if (!this.userConfig.kbSignAlg) throw new SDJWTException("Key Binding sign algorithm not specified");
973
+ const { payload } = options;
974
+ const kbJwt = new KBJwt({
975
+ header: {
976
+ typ: KB_JWT_TYP,
977
+ alg: this.userConfig.kbSignAlg
978
+ },
979
+ payload: {
980
+ ...payload,
981
+ sd_hash: sdHash
982
+ }
983
+ });
984
+ await kbJwt.sign(this.userConfig.kbSigner);
985
+ return kbJwt;
986
+ }
987
+ async SignJwt(jwt) {
988
+ if (!this.userConfig.signer) throw new SDJWTException("Signer not found");
989
+ await jwt.sign(this.userConfig.signer);
990
+ return jwt;
991
+ }
992
+ async VerifyJwt(jwt, options) {
993
+ if (!this.userConfig.verifier) throw new SDJWTException("Verifier not found");
994
+ return jwt.verify(this.userConfig.verifier, options);
995
+ }
996
+ async issue(payload, disclosureFrame, options) {
997
+ if (!this.userConfig.hasher) throw new SDJWTException("Hasher not found");
998
+ if (!this.userConfig.saltGenerator) throw new SDJWTException("SaltGenerator not found");
999
+ if (!this.userConfig.signAlg) throw new SDJWTException("sign alogrithm not specified");
1000
+ if (this.userConfig.signAlg === "none") throw new SDJWTException("sign algorithm \"none\" is not allowed");
1001
+ this.validateReservedFields(payload);
1002
+ this.validateDisclosureFrame(disclosureFrame);
1003
+ const hasher = this.userConfig.hasher;
1004
+ const hashAlg = this.userConfig.hashAlg ?? SDJwtInstance.DEFAULT_hashAlg;
1005
+ if (!(this.userConfig.allowedDisclosureHashAlgorithms ?? DEFAULT_SECURE_HASH_ALGORITHMS).includes(hashAlg)) throw new SDJWTException(`Disallowed hash algorithm: ${hashAlg}`);
1006
+ const { packedClaims, disclosures } = await pack(payload, disclosureFrame, {
1007
+ hasher,
1008
+ alg: hashAlg
1009
+ }, this.userConfig.saltGenerator);
1010
+ const alg = this.userConfig.signAlg;
1011
+ const OptionHeader = options?.header ?? {};
1012
+ const jwt = new Jwt({
1013
+ header: {
1014
+ ...this.userConfig.omitTyp ? OptionHeader : {
1015
+ typ: this.type,
1016
+ ...OptionHeader
1017
+ },
1018
+ alg
1019
+ },
1020
+ payload: {
1021
+ ...packedClaims,
1022
+ _sd_alg: disclosureFrame ? hashAlg : void 0
1023
+ }
1024
+ });
1025
+ await this.SignJwt(jwt);
1026
+ return new SDJwt({
1027
+ jwt,
1028
+ disclosures
1029
+ }).encodeSDJwt();
1030
+ }
1031
+ /**
1032
+ * Validates if the payload contains any reserved claim names. If so it will throw an error.
1033
+ * @param payload
1034
+ * @returns
1035
+ */
1036
+ validateReservedFields(payload) {
1037
+ validateReservedFieldsInternal(payload);
1038
+ }
1039
+ validateDisclosureFrame(_disclosureFrame) {}
1040
+ async present(encodedSDJwt, presentationFrame, options) {
1041
+ if (!this.userConfig.hasher) throw new SDJWTException("Hasher not found");
1042
+ const hasher = this.userConfig.hasher;
1043
+ const sdjwt = await SDJwt.fromEncode(encodedSDJwt, hasher);
1044
+ if (sdjwt.kbJwt) throw new SDJWTException("Holder cannot present an SD-JWT with KB-JWT");
1045
+ if (!sdjwt.jwt?.payload) throw new SDJWTException("Payload not found");
1046
+ const presentSdJwtWithoutKb = await sdjwt.present(presentationFrame, hasher);
1047
+ if (!options?.kb) return presentSdJwtWithoutKb;
1048
+ const sdHashStr = await this.calculateSDHash(presentSdJwtWithoutKb, sdjwt, hasher);
1049
+ sdjwt.kbJwt = await this.createKBJwt(options.kb, sdHashStr);
1050
+ return sdjwt.present(presentationFrame, hasher);
1051
+ }
1052
+ async verify(encodedSDJwt, options) {
1053
+ if (!this.userConfig.hasher) throw new SDJWTException("Hasher not found");
1054
+ const hasher = this.userConfig.hasher;
1055
+ const sdjwt = await SDJwt.fromEncode(encodedSDJwt, hasher);
1056
+ if (!sdjwt.jwt?.payload) throw new SDJWTException("Invalid SD JWT");
1057
+ const { payload, header } = await this.validate(encodedSDJwt, options);
1058
+ if (options?.requiredClaimKeys) {
1059
+ const keys = await sdjwt.keys(hasher);
1060
+ const missingKeys = options.requiredClaimKeys.filter((k) => !keys.includes(k));
1061
+ if (missingKeys.length > 0) throw new SDJWTException(`Missing required claim keys: ${missingKeys.join(", ")}`);
1062
+ }
1063
+ if (!options?.keyBindingNonce) return {
1064
+ payload,
1065
+ header
1066
+ };
1067
+ if (!sdjwt.kbJwt) throw new SDJWTException("Key Binding JWT not exist");
1068
+ if (!this.userConfig.kbVerifier) throw new SDJWTException("Key Binding Verifier not found");
1069
+ const kb = await sdjwt.kbJwt.verifyKB({
1070
+ verifier: this.userConfig.kbVerifier,
1071
+ payload,
1072
+ nonce: options.keyBindingNonce,
1073
+ options
1074
+ });
1075
+ if (!kb) throw new Error("signature is not valid");
1076
+ const sdHashfromKb = kb.payload.sd_hash;
1077
+ const presentSdJwtWithoutKb = new SDJwt({
1078
+ jwt: sdjwt.jwt,
1079
+ disclosures: sdjwt.disclosures
1080
+ }).encodeSDJwt();
1081
+ if (await this.calculateSDHash(presentSdJwtWithoutKb, sdjwt, hasher) !== sdHashfromKb) throw new SDJWTException("Invalid sd_hash in Key Binding JWT");
1082
+ return {
1083
+ payload,
1084
+ header,
1085
+ kb
1086
+ };
1087
+ }
1088
+ /**
1089
+ * Safe verification that collects all errors instead of failing fast.
1090
+ * Returns a result object with either the verified data or an array of all errors.
1091
+ *
1092
+ * @param encodedSDJwt - The encoded SD-JWT to verify
1093
+ * @param options - Verification options
1094
+ * @returns A SafeVerifyResult containing either success data or collected errors
1095
+ */
1096
+ async safeVerify(encodedSDJwt, options) {
1097
+ const errors = [];
1098
+ const addError = (code, message, details) => {
1099
+ errors.push({
1100
+ code,
1101
+ message,
1102
+ details
1103
+ });
1104
+ };
1105
+ const exceptionToCode = (error) => {
1106
+ const message = error.message.toLowerCase();
1107
+ if (message.includes("hasher not found")) return "HASHER_NOT_FOUND";
1108
+ if (message.includes("verifier not found")) return "VERIFIER_NOT_FOUND";
1109
+ if (message.includes("invalid sd jwt") || message.includes("invalid jwt")) return "INVALID_SD_JWT";
1110
+ if (message.includes("not yet valid")) return "JWT_NOT_YET_VALID";
1111
+ if (message.includes("expired")) return "JWT_EXPIRED";
1112
+ if (message.includes("signature")) return "INVALID_JWT_SIGNATURE";
1113
+ if (message.includes("missing required claim")) return "MISSING_REQUIRED_CLAIMS";
1114
+ if (message.includes("key binding jwt not exist")) return "KEY_BINDING_JWT_MISSING";
1115
+ if (message.includes("key binding verifier not found")) return "KEY_BINDING_VERIFIER_NOT_FOUND";
1116
+ if (message.includes("sd_hash")) return "KEY_BINDING_SD_HASH_INVALID";
1117
+ return "UNKNOWN_ERROR";
1118
+ };
1119
+ if (!this.userConfig.hasher) addError("HASHER_NOT_FOUND", "Hasher not found");
1120
+ if (!this.userConfig.verifier) addError("VERIFIER_NOT_FOUND", "Verifier not found");
1121
+ if (errors.length > 0) return {
1122
+ success: false,
1123
+ errors
1124
+ };
1125
+ if (!this.userConfig.hasher) throw new SDJWTException("Hasher not found");
1126
+ const hasher = this.userConfig.hasher;
1127
+ let sdjwt;
1128
+ let payload;
1129
+ let header;
1130
+ try {
1131
+ sdjwt = await SDJwt.fromEncode(encodedSDJwt, hasher);
1132
+ if (!sdjwt.jwt?.payload) addError("INVALID_SD_JWT", "Invalid SD JWT: missing JWT or payload");
1133
+ } catch (e) {
1134
+ const error = ensureError(e);
1135
+ addError("INVALID_SD_JWT", `Failed to decode SD-JWT: ${error.message}`, error);
1136
+ }
1137
+ if (sdjwt?.jwt) try {
1138
+ header = (await this.VerifyJwt(sdjwt.jwt, {
1139
+ ...options,
1140
+ skipJwtClaimValidation: true
1141
+ })).header;
1142
+ payload = await sdjwt.getClaims(hasher);
1143
+ validateJwtPayload(payload, options);
1144
+ } catch (e) {
1145
+ const error = ensureError(e);
1146
+ addError(exceptionToCode(error), error.message, error);
1147
+ }
1148
+ if (sdjwt && options?.requiredClaimKeys) try {
1149
+ const keys = await sdjwt.keys(hasher);
1150
+ const missingKeys = options.requiredClaimKeys.filter((k) => !keys.includes(k));
1151
+ if (missingKeys.length > 0) addError("MISSING_REQUIRED_CLAIMS", `Missing required claim keys: ${missingKeys.join(", ")}`, { missingKeys });
1152
+ } catch (e) {
1153
+ const error = ensureError(e);
1154
+ addError("UNKNOWN_ERROR", `Failed to check required claims: ${error.message}`, error);
1155
+ }
1156
+ let kb;
1157
+ if (options?.keyBindingNonce && sdjwt) {
1158
+ if (!sdjwt.kbJwt) addError("KEY_BINDING_JWT_MISSING", "Key Binding JWT not exist");
1159
+ else if (!this.userConfig.kbVerifier) addError("KEY_BINDING_VERIFIER_NOT_FOUND", "Key Binding Verifier not found");
1160
+ else if (payload) try {
1161
+ const kbResult = await sdjwt.kbJwt.verifyKB({
1162
+ verifier: this.userConfig.kbVerifier,
1163
+ payload,
1164
+ nonce: options.keyBindingNonce,
1165
+ options
1166
+ });
1167
+ if (!kbResult) addError("KEY_BINDING_SIGNATURE_INVALID", "Key binding signature is not valid");
1168
+ else {
1169
+ kb = kbResult;
1170
+ const presentSdJwtWithoutKb = new SDJwt({
1171
+ jwt: sdjwt.jwt,
1172
+ disclosures: sdjwt.disclosures
1173
+ }).encodeSDJwt();
1174
+ const sdHashStr = await this.calculateSDHash(presentSdJwtWithoutKb, sdjwt, hasher);
1175
+ if (sdHashStr !== kbResult.payload.sd_hash) addError("KEY_BINDING_SD_HASH_INVALID", "Invalid sd_hash in Key Binding JWT", {
1176
+ expected: sdHashStr,
1177
+ received: kbResult.payload.sd_hash
1178
+ });
1179
+ }
1180
+ } catch (e) {
1181
+ const error = ensureError(e);
1182
+ addError("KEY_BINDING_SIGNATURE_INVALID", `Key binding verification failed: ${error.message}`, error);
1183
+ }
1184
+ }
1185
+ if (errors.length > 0) return {
1186
+ success: false,
1187
+ errors
1188
+ };
1189
+ return {
1190
+ success: true,
1191
+ data: {
1192
+ payload,
1193
+ header,
1194
+ kb
1195
+ }
1196
+ };
1197
+ }
1198
+ async calculateSDHash(presentSdJwtWithoutKb, sdjwt, hasher) {
1199
+ if (!sdjwt.jwt?.payload) throw new SDJWTException("Invalid SD JWT");
1200
+ const { _sd_alg } = getSDAlgAndPayload(sdjwt.jwt.payload);
1201
+ const sdHash = await hasher(presentSdJwtWithoutKb, _sd_alg);
1202
+ return (0, _owf_identity_common.uint8ArrayToBase64Url)(sdHash);
1203
+ }
1204
+ /**
1205
+ * This function is for validating the SD JWT
1206
+ * Checking signature, if provided the iat and exp when provided and return its the claims
1207
+ * @param encodedSDJwt
1208
+ * @param options
1209
+ * @returns
1210
+ */
1211
+ async validate(encodedSDJwt, options) {
1212
+ if (!this.userConfig.hasher) throw new SDJWTException("Hasher not found");
1213
+ const hasher = this.userConfig.hasher;
1214
+ const sdjwt = await SDJwt.fromEncode(encodedSDJwt, hasher);
1215
+ if (!sdjwt.jwt) throw new SDJWTException("Invalid SD JWT");
1216
+ const verifiedPayloads = await this.VerifyJwt(sdjwt.jwt, {
1217
+ ...options,
1218
+ skipJwtClaimValidation: true
1219
+ });
1220
+ const claims = await sdjwt.getClaims(hasher);
1221
+ validateReservedFieldsInternal(claims);
1222
+ validateJwtPayload(claims, options);
1223
+ return {
1224
+ payload: claims,
1225
+ header: verifiedPayloads.header
1226
+ };
1227
+ }
1228
+ config(newConfig) {
1229
+ this.userConfig = {
1230
+ ...this.userConfig,
1231
+ ...newConfig
1232
+ };
1233
+ }
1234
+ encode(sdJwt) {
1235
+ return sdJwt.encodeSDJwt();
1236
+ }
1237
+ decode(endcodedSDJwt) {
1238
+ if (!this.userConfig.hasher) throw new SDJWTException("Hasher not found");
1239
+ return SDJwt.fromEncode(endcodedSDJwt, this.userConfig.hasher);
1240
+ }
1241
+ async keys(endcodedSDJwt) {
1242
+ if (!this.userConfig.hasher) throw new SDJWTException("Hasher not found");
1243
+ return (await SDJwt.fromEncode(endcodedSDJwt, this.userConfig.hasher)).keys(this.userConfig.hasher);
1244
+ }
1245
+ async presentableKeys(endcodedSDJwt) {
1246
+ if (!this.userConfig.hasher) throw new SDJWTException("Hasher not found");
1247
+ return (await SDJwt.fromEncode(endcodedSDJwt, this.userConfig.hasher)).presentableKeys(this.userConfig.hasher);
1248
+ }
1249
+ async getClaims(endcodedSDJwt) {
1250
+ if (!this.userConfig.hasher) throw new SDJWTException("Hasher not found");
1251
+ return (await SDJwt.fromEncode(endcodedSDJwt, this.userConfig.hasher)).getClaims(this.userConfig.hasher);
1252
+ }
1253
+ toFlattenJSON(endcodedSDJwt) {
1254
+ return FlattenJSON.fromEncode(endcodedSDJwt);
1255
+ }
1256
+ toGeneralJSON(endcodedSDJwt) {
1257
+ return GeneralJSON.fromEncode(endcodedSDJwt);
1258
+ }
1259
+ };
1260
+ var SDJwtGeneralJSONInstance = class {
1261
+ static {
1262
+ this.DEFAULT_hashAlg = "sha-256";
1263
+ }
1264
+ constructor(userConfig) {
1265
+ this.userConfig = {};
1266
+ if (userConfig) {
1267
+ if (userConfig.hashAlg && !IANA_HASH_ALGORITHMS.includes(userConfig.hashAlg)) throw new SDJWTException(`Invalid hash algorithm: ${userConfig.hashAlg}`);
1268
+ const allowedDisclosureHashAlgorithms = userConfig.allowedDisclosureHashAlgorithms ?? DEFAULT_SECURE_HASH_ALGORITHMS;
1269
+ if (userConfig.hashAlg && !allowedDisclosureHashAlgorithms.includes(userConfig.hashAlg)) throw new SDJWTException(`Disallowed hash algorithm: ${userConfig.hashAlg}`);
1270
+ this.userConfig = userConfig;
1271
+ }
1272
+ }
1273
+ async createKBJwt(options, sdHash) {
1274
+ if (!this.userConfig.kbSigner) throw new SDJWTException("Key Binding Signer not found");
1275
+ if (!this.userConfig.kbSignAlg) throw new SDJWTException("Key Binding sign algorithm not specified");
1276
+ const { payload } = options;
1277
+ const kbJwt = new KBJwt({
1278
+ header: {
1279
+ typ: KB_JWT_TYP,
1280
+ alg: this.userConfig.kbSignAlg
1281
+ },
1282
+ payload: {
1283
+ ...payload,
1284
+ sd_hash: sdHash
1285
+ }
1286
+ });
1287
+ await kbJwt.sign(this.userConfig.kbSigner);
1288
+ return kbJwt;
1289
+ }
1290
+ encodeObj(obj) {
1291
+ return (0, _owf_identity_common.base64urlEncode)(JSON.stringify(obj));
1292
+ }
1293
+ async issue(payload, disclosureFrame, options) {
1294
+ if (!this.userConfig.hasher) throw new SDJWTException("Hasher not found");
1295
+ if (!this.userConfig.saltGenerator) throw new SDJWTException("SaltGenerator not found");
1296
+ this.validateReservedFields(payload);
1297
+ this.validateDisclosureFrame(disclosureFrame);
1298
+ const hasher = this.userConfig.hasher;
1299
+ const hashAlg = this.userConfig.hashAlg ?? SDJwtInstance.DEFAULT_hashAlg;
1300
+ const { packedClaims, disclosures } = await pack(payload, disclosureFrame, {
1301
+ hasher,
1302
+ alg: hashAlg
1303
+ }, this.userConfig.saltGenerator);
1304
+ const encodedSDJwtPayload = this.encodeObj({
1305
+ ...packedClaims,
1306
+ _sd_alg: disclosureFrame ? hashAlg : void 0
1307
+ });
1308
+ return new GeneralJSON({
1309
+ payload: encodedSDJwtPayload,
1310
+ disclosures: disclosures.map((disclosure) => disclosure.encode()),
1311
+ signatures: await Promise.all(options.sigs.map(async (s) => {
1312
+ const { signer, alg, kid, header } = s;
1313
+ const protectedHeader = {
1314
+ typ: this.type,
1315
+ alg,
1316
+ kid,
1317
+ ...header
1318
+ };
1319
+ const encodedProtectedHeader = this.encodeObj(protectedHeader);
1320
+ return {
1321
+ protected: encodedProtectedHeader,
1322
+ signature: await signer(`${encodedProtectedHeader}.${encodedSDJwtPayload}`)
1323
+ };
1324
+ }))
1325
+ });
1326
+ }
1327
+ /**
1328
+ * Validates if the payload contains any reserved claim names. If so it will throw an error.
1329
+ * @param payload
1330
+ * @returns
1331
+ */
1332
+ validateReservedFields(payload) {
1333
+ validateReservedFieldsInternal(payload);
1334
+ }
1335
+ validateDisclosureFrame(_disclosureFrame) {}
1336
+ async present(generalJSON, presentationFrame, options) {
1337
+ if (!this.userConfig.hasher) throw new SDJWTException("Hasher not found");
1338
+ const hasher = this.userConfig.hasher;
1339
+ const encodedSDJwt = generalJSON.toEncoded(0);
1340
+ const sdjwt = await SDJwt.fromEncode(encodedSDJwt, hasher);
1341
+ if (sdjwt.kbJwt) throw new SDJWTException("Holder cannot present an SD-JWT with KB-JWT");
1342
+ if (!sdjwt.jwt?.payload) throw new SDJWTException("Payload not found");
1343
+ const encodedDisclosures = (await sdjwt.getPresentDisclosures(presentationFrame, hasher)).map((d) => d.encode());
1344
+ const presentedGeneralJSON = new GeneralJSON({
1345
+ payload: generalJSON.payload,
1346
+ disclosures: encodedDisclosures,
1347
+ signatures: generalJSON.signatures
1348
+ });
1349
+ if (!options?.kb) return presentedGeneralJSON;
1350
+ const presentSdJwtWithoutKb = await sdjwt.present(presentationFrame, hasher);
1351
+ const sdHashStr = await this.calculateSDHash(presentSdJwtWithoutKb, sdjwt, hasher);
1352
+ presentedGeneralJSON.kb_jwt = (await this.createKBJwt(options.kb, sdHashStr)).encodeJwt();
1353
+ return presentedGeneralJSON;
1354
+ }
1355
+ async verify(generalJSON, options) {
1356
+ if (!this.userConfig.hasher) throw new SDJWTException("Hasher not found");
1357
+ const hasher = this.userConfig.hasher;
1358
+ const { payload, headers } = await this.validate(generalJSON, options);
1359
+ const encodedSDJwt = generalJSON.toEncoded(0);
1360
+ const sdjwt = await SDJwt.fromEncode(encodedSDJwt, hasher);
1361
+ if (!sdjwt.jwt?.payload) throw new SDJWTException("Invalid SD JWT");
1362
+ if (options?.requiredClaimKeys) {
1363
+ const keys = await sdjwt.keys(hasher);
1364
+ const missingKeys = options?.requiredClaimKeys.filter((k) => !keys.includes(k));
1365
+ if (missingKeys.length > 0) throw new SDJWTException(`Missing required claim keys: ${missingKeys.join(", ")}`);
1366
+ }
1367
+ if (!options?.keyBindingNonce) return {
1368
+ payload,
1369
+ headers
1370
+ };
1371
+ if (!sdjwt.kbJwt) throw new SDJWTException("Key Binding JWT not exist");
1372
+ if (!this.userConfig.kbVerifier) throw new SDJWTException("Key Binding Verifier not found");
1373
+ const kb = await sdjwt.kbJwt.verifyKB({
1374
+ verifier: this.userConfig.kbVerifier,
1375
+ payload,
1376
+ nonce: options.keyBindingNonce,
1377
+ options
1378
+ });
1379
+ if (!kb) throw new Error("signature is not valid");
1380
+ const sdHashfromKb = kb.payload.sd_hash;
1381
+ const presentSdJwtWithoutKb = new SDJwt({
1382
+ jwt: sdjwt.jwt,
1383
+ disclosures: sdjwt.disclosures
1384
+ }).encodeSDJwt();
1385
+ if (await this.calculateSDHash(presentSdJwtWithoutKb, sdjwt, hasher) !== sdHashfromKb) throw new SDJWTException("Invalid sd_hash in Key Binding JWT");
1386
+ return {
1387
+ payload,
1388
+ headers,
1389
+ kb
1390
+ };
1391
+ }
1392
+ async calculateSDHash(presentSdJwtWithoutKb, sdjwt, hasher) {
1393
+ if (!sdjwt.jwt?.payload) throw new SDJWTException("Invalid SD JWT");
1394
+ const { _sd_alg } = getSDAlgAndPayload(sdjwt.jwt.payload);
1395
+ const sdHash = await hasher(presentSdJwtWithoutKb, _sd_alg);
1396
+ return (0, _owf_identity_common.uint8ArrayToBase64Url)(sdHash);
1397
+ }
1398
+ async validate(generalJSON, options) {
1399
+ if (!this.userConfig.hasher) throw new SDJWTException("Hasher not found");
1400
+ if (!this.userConfig.verifier) throw new SDJWTException("Verifier not found");
1401
+ const hasher = this.userConfig.hasher;
1402
+ const verifier = this.userConfig.verifier;
1403
+ const { payload, signatures } = generalJSON;
1404
+ const results = await Promise.all(signatures.map(async (s) => {
1405
+ const { protected: encodedHeader, signature } = s;
1406
+ const verified = await verifier(`${encodedHeader}.${payload}`, signature, {
1407
+ ...options,
1408
+ skipJwtClaimValidation: true
1409
+ });
1410
+ const header = decodeBase64urlJsonStrict(encodedHeader, "Invalid JWT");
1411
+ if (typeof header.alg !== "string" || header.alg === "none") throw new SDJWTException("Verify Error: alg \"none\" is not allowed");
1412
+ if (options?.allowedIssuerAlgorithms && !options.allowedIssuerAlgorithms.includes(header.alg)) throw new SDJWTException(`Verify Error: Disallowed alg ${header.alg}`);
1413
+ return {
1414
+ verified,
1415
+ header
1416
+ };
1417
+ }));
1418
+ if (!results.every((r) => r.verified)) throw new SDJWTException("Signature is not valid");
1419
+ const encodedSDJwt = generalJSON.toEncoded(0);
1420
+ const sdjwt = await SDJwt.fromEncode(encodedSDJwt, hasher);
1421
+ if (!sdjwt.jwt) throw new SDJWTException("Invalid SD JWT");
1422
+ const claims = await sdjwt.getClaims(hasher);
1423
+ validateReservedFieldsInternal(claims);
1424
+ validateJwtPayload(claims, options);
1425
+ return {
1426
+ payload: claims,
1427
+ headers: results.map((r) => r.header)
1428
+ };
1429
+ }
1430
+ config(newConfig) {
1431
+ this.userConfig = {
1432
+ ...this.userConfig,
1433
+ ...newConfig
1434
+ };
1435
+ }
1436
+ encode(sdJwt, index) {
1437
+ return sdJwt.toEncoded(index);
1438
+ }
1439
+ decode(endcodedSDJwt) {
1440
+ return GeneralJSON.fromEncode(endcodedSDJwt);
1441
+ }
1442
+ async keys(generalSdjwt) {
1443
+ if (!this.userConfig.hasher) throw new SDJWTException("Hasher not found");
1444
+ const endcodedSDJwt = generalSdjwt.toEncoded(0);
1445
+ return (await SDJwt.fromEncode(endcodedSDJwt, this.userConfig.hasher)).keys(this.userConfig.hasher);
1446
+ }
1447
+ async presentableKeys(generalSdjwt) {
1448
+ if (!this.userConfig.hasher) throw new SDJWTException("Hasher not found");
1449
+ const endcodedSDJwt = generalSdjwt.toEncoded(0);
1450
+ return (await SDJwt.fromEncode(endcodedSDJwt, this.userConfig.hasher)).presentableKeys(this.userConfig.hasher);
1451
+ }
1452
+ async getClaims(generalSdjwt) {
1453
+ if (!this.userConfig.hasher) throw new SDJWTException("Hasher not found");
1454
+ const endcodedSDJwt = generalSdjwt.toEncoded(0);
1455
+ return (await SDJwt.fromEncode(endcodedSDJwt, this.userConfig.hasher)).getClaims(this.userConfig.hasher);
1456
+ }
1457
+ };
1458
+ //#endregion
1459
+ exports.DEFAULT_SECURE_HASH_ALGORITHMS = DEFAULT_SECURE_HASH_ALGORITHMS;
1460
+ exports.Disclosure = Disclosure;
1461
+ exports.FlattenJSON = FlattenJSON;
1462
+ exports.GeneralJSON = GeneralJSON;
1463
+ exports.IANA_HASH_ALGORITHMS = IANA_HASH_ALGORITHMS;
1464
+ exports.Jwt = Jwt;
1465
+ exports.KBJwt = KBJwt;
1466
+ exports.KB_JWT_TYP = KB_JWT_TYP;
1467
+ exports.SDJWTException = SDJWTException;
1468
+ exports.SDJwt = SDJwt;
1469
+ exports.SDJwtGeneralJSONInstance = SDJwtGeneralJSONInstance;
1470
+ exports.SDJwtInstance = SDJwtInstance;
1471
+ exports.SD_DECOY = SD_DECOY;
1472
+ exports.SD_DIGEST = SD_DIGEST;
1473
+ exports.SD_LIST_KEY = SD_LIST_KEY;
1474
+ exports.SD_SEPARATOR = SD_SEPARATOR;
1475
+ Object.defineProperty(exports, "base64UrlToUint8Array", {
1476
+ enumerable: true,
1477
+ get: function() {
1478
+ return _owf_identity_common.base64UrlToUint8Array;
1479
+ }
1480
+ });
1481
+ Object.defineProperty(exports, "base64urlDecode", {
1482
+ enumerable: true,
1483
+ get: function() {
1484
+ return _owf_identity_common.base64urlDecode;
1485
+ }
1486
+ });
1487
+ Object.defineProperty(exports, "base64urlEncode", {
1488
+ enumerable: true,
1489
+ get: function() {
1490
+ return _owf_identity_common.base64urlEncode;
1491
+ }
1492
+ });
1493
+ exports.createDecoy = createDecoy;
1494
+ exports.createHashMapping = createHashMapping;
1495
+ exports.createHashMappingForSerializedDisclosure = createHashMappingForSerializedDisclosure;
1496
+ exports.createHashMappingSync = createHashMappingSync;
1497
+ exports.decodeJwt = decodeJwt;
1498
+ exports.decodeSdJwt = decodeSdJwt;
1499
+ exports.decodeSdJwtSync = decodeSdJwtSync;
1500
+ exports.encodePath = encodePath;
1501
+ exports.encodePathSegment = encodePathSegment;
1502
+ exports.ensureError = ensureError;
1503
+ exports.getClaims = getClaims;
1504
+ exports.getClaimsSync = getClaimsSync;
1505
+ exports.getSDAlgAndPayload = getSDAlgAndPayload;
1506
+ exports.listKeys = listKeys;
1507
+ exports.pack = pack;
1508
+ exports.present = present;
1509
+ exports.presentSync = presentSync;
1510
+ exports.presentableKeys = presentableKeys;
1511
+ exports.presentableKeysSync = presentableKeysSync;
1512
+ exports.selectDisclosures = selectDisclosures;
1513
+ exports.splitSdJwt = splitSdJwt;
1514
+ exports.transformPresentationFrame = transformPresentationFrame;
1515
+ Object.defineProperty(exports, "uint8ArrayToBase64Url", {
1516
+ enumerable: true,
1517
+ get: function() {
1518
+ return _owf_identity_common.uint8ArrayToBase64Url;
1519
+ }
1520
+ });
1521
+ exports.unpack = unpack;
1522
+ exports.unpackObj = unpackObj;
1523
+ exports.unpackSync = unpackSync;
1524
+ exports.validateJwtPayload = validateJwtPayload;
1525
+
1526
+ //# sourceMappingURL=index.cjs.map