@pagopa/io-wallet-utils 1.5.8 → 2.0.0-apt

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -32,46 +32,63 @@ var index_exports = {};
32
32
  __export(index_exports, {
33
33
  CLOCK_SKEW_TOLERANCE_SECONDS: () => CLOCK_SKEW_TOLERANCE_SECONDS,
34
34
  CONTENT_TYPES: () => CONTENT_TYPES,
35
- ContentType: () => import_utils.ContentType,
35
+ ContentType: () => ContentType,
36
36
  HEADERS: () => HEADERS,
37
- HashAlgorithm: () => import_oauth2.HashAlgorithm,
37
+ HashAlgorithm: () => HashAlgorithm,
38
38
  IoWalletSdkConfig: () => IoWalletSdkConfig,
39
39
  ItWalletSpecsVersion: () => ItWalletSpecsVersion,
40
40
  ItWalletSpecsVersionError: () => ItWalletSpecsVersionError,
41
- JsonParseError: () => import_utils.JsonParseError,
41
+ JsonParseError: () => JsonParseError,
42
+ JwtParseError: () => JwtParseError,
43
+ JwtVerificationError: () => JwtVerificationError,
42
44
  MAX_IAT_AGE_SECONDS: () => MAX_IAT_AGE_SECONDS,
45
+ MAX_JTI_LENGTH: () => MAX_JTI_LENGTH,
43
46
  UnexpectedStatusCodeError: () => UnexpectedStatusCodeError,
44
47
  ValidationError: () => ValidationError,
45
- addSecondsToDate: () => import_utils.addSecondsToDate,
46
- calculateJwkThumbprint: () => import_oauth2.calculateJwkThumbprint,
47
- createFetcher: () => import_utils.createFetcher,
48
+ addSecondsToDate: () => addSecondsToDate,
49
+ calculateJwkThumbprint: () => calculateJwkThumbprint,
50
+ createFetcher: () => createFetcher,
48
51
  createVersionDispatcher: () => createVersionDispatcher,
49
- dateToSeconds: () => import_utils.dateToSeconds,
50
- decodeBase64: () => import_utils.decodeBase64,
51
- decodeJwt: () => import_oauth2.decodeJwt,
52
- decodeUtf8String: () => import_utils.decodeUtf8String,
52
+ dateToSeconds: () => dateToSeconds,
53
+ decodeBase64: () => decodeBase64,
54
+ decodeJwt: () => decodeJwt,
55
+ decodeJwtHeader: () => decodeJwtHeader,
56
+ decodeUtf8String: () => decodeUtf8String,
53
57
  dispatchByVersion: () => dispatchByVersion,
54
- encodeToBase64Url: () => import_utils.encodeToBase64Url,
55
- encodeToUtf8String: () => import_utils.encodeToUtf8String,
58
+ encodeToBase64Url: () => encodeToBase64Url,
59
+ encodeToUtf8String: () => encodeToUtf8String,
56
60
  formatError: () => formatError,
57
61
  formatZodError: () => formatZodError,
58
62
  hasConfigVersion: () => hasConfigVersion,
59
63
  hasStatusOrThrow: () => hasStatusOrThrow,
60
- objectToQueryParams: () => import_utils.objectToQueryParams,
61
- parseIfJson: () => import_utils.parseIfJson,
64
+ jwtHeaderFromJwtSigner: () => jwtHeaderFromJwtSigner,
65
+ jwtSignerFromJwt: () => jwtSignerFromJwt,
66
+ objectToQueryParams: () => objectToQueryParams,
67
+ parseIfJson: () => parseIfJson,
62
68
  parseRawHttpResponse: () => parseRawHttpResponse,
63
69
  parseWithErrorHandling: () => parseWithErrorHandling,
64
70
  serializeAttrs: () => serializeAttrs,
65
- setGlobalConfig: () => import_utils.setGlobalConfig,
66
- stringToJsonWithErrorHandling: () => import_utils.stringToJsonWithErrorHandling,
71
+ stringToJsonWithErrorHandling: () => stringToJsonWithErrorHandling,
72
+ verifyJwt: () => verifyJwt,
67
73
  verifyJwtIatOrThrow: () => verifyJwtIatOrThrow,
74
+ zAlgValueNotNone: () => zAlgValueNotNone,
75
+ zCertificateChain: () => zCertificateChain,
76
+ zCompactJwe: () => zCompactJwe,
77
+ zCompactJwt: () => zCompactJwt,
68
78
  zHttpMethod: () => zHttpMethod,
69
- zItwSupportedSignatureAlg: () => zItwSupportedSignatureAlg
79
+ zItwSupportedSignatureAlg: () => zItwSupportedSignatureAlg,
80
+ zJwk: () => zJwk,
81
+ zJwkSet: () => zJwkSet,
82
+ zJwtConfirmationPayload: () => zJwtConfirmationPayload,
83
+ zJwtHeader: () => zJwtHeader,
84
+ zJwtPayload: () => zJwtPayload,
85
+ zTrustChain: () => zTrustChain
70
86
  });
71
87
  module.exports = __toCommonJS(index_exports);
72
88
 
73
89
  // src/config.ts
74
90
  var ItWalletSpecsVersion = /* @__PURE__ */ ((ItWalletSpecsVersion2) => {
91
+ ItWalletSpecsVersion2["APTITUDE"] = "APTITUDE";
75
92
  ItWalletSpecsVersion2["V1_0"] = "V1_0";
76
93
  ItWalletSpecsVersion2["V1_3"] = "V1_3";
77
94
  ItWalletSpecsVersion2["V1_4"] = "V1_4";
@@ -120,6 +137,59 @@ var HEADERS = {
120
137
  var MAX_IAT_AGE_SECONDS = 5 * 60;
121
138
  var CLOCK_SKEW_TOLERANCE_SECONDS = 60;
122
139
 
140
+ // src/content-type.ts
141
+ var ContentType = /* @__PURE__ */ ((ContentType2) => {
142
+ ContentType2["Html"] = "text/html";
143
+ ContentType2["Json"] = "application/json";
144
+ ContentType2["JwkSet"] = "application/jwk-set+json";
145
+ ContentType2["Jwt"] = "application/jwt";
146
+ ContentType2["OAuthAuthorizationRequestJwt"] = "application/oauth-authz-req+jwt";
147
+ ContentType2["XWwwFormUrlencoded"] = "application/x-www-form-urlencoded";
148
+ return ContentType2;
149
+ })(ContentType || {});
150
+
151
+ // src/crypto/hash.ts
152
+ var HashAlgorithm = /* @__PURE__ */ ((HashAlgorithm2) => {
153
+ HashAlgorithm2["Sha256"] = "sha-256";
154
+ HashAlgorithm2["Sha384"] = "sha-384";
155
+ HashAlgorithm2["Sha512"] = "sha-512";
156
+ return HashAlgorithm2;
157
+ })(HashAlgorithm || {});
158
+
159
+ // src/encoding.ts
160
+ var utf8Encoder = new TextEncoder();
161
+ var utf8Decoder = new TextDecoder();
162
+ function base64UrlToBase64(base64) {
163
+ const normalized = base64.replace(/-/g, "+").replace(/_/g, "/");
164
+ const paddingLength = normalized.length % 4;
165
+ return paddingLength === 0 ? normalized : normalized.padEnd(normalized.length + (4 - paddingLength), "=");
166
+ }
167
+ function base64ToBase64Url(base64) {
168
+ return base64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
169
+ }
170
+ function encodeBase64(data) {
171
+ let binary = "";
172
+ for (const byte of data) {
173
+ binary += String.fromCharCode(byte);
174
+ }
175
+ return btoa(binary);
176
+ }
177
+ function decodeUtf8String(value) {
178
+ return utf8Encoder.encode(value);
179
+ }
180
+ function encodeToUtf8String(data) {
181
+ return utf8Decoder.decode(data);
182
+ }
183
+ function decodeBase64(base64) {
184
+ const binary = atob(base64UrlToBase64(base64));
185
+ return Uint8Array.from(binary, (char) => char.charCodeAt(0));
186
+ }
187
+ function encodeToBase64Url(data) {
188
+ return base64ToBase64Url(
189
+ encodeBase64(typeof data === "string" ? decodeUtf8String(data) : data)
190
+ );
191
+ }
192
+
123
193
  // src/errors/parse.ts
124
194
  var constants = {
125
195
  identifierRegex: /[$_\p{ID_Start}][$\u200c\u200d\p{ID_Continue}]*/u,
@@ -178,6 +248,27 @@ function formatZodError(error) {
178
248
  }
179
249
 
180
250
  // src/errors/errors.ts
251
+ var JsonParseError = class extends Error {
252
+ constructor(message, jsonString) {
253
+ super(`${message}
254
+ ${jsonString}`);
255
+ this.name = "JsonParseError";
256
+ }
257
+ };
258
+ var JwtParseError = class extends Error {
259
+ constructor(message) {
260
+ super(message ?? "Error parsing jwt");
261
+ this.name = "JwtParseError";
262
+ }
263
+ };
264
+ var JwtVerificationError = class extends Error {
265
+ constructor(message, options) {
266
+ const errorMessage = message ?? "Error verifying jwt.";
267
+ const causeMessage = options?.cause instanceof Error ? ` ${options.cause.message}` : options?.cause ? ` ${String(options.cause)}` : "";
268
+ super(`${errorMessage}${causeMessage}`, options);
269
+ this.name = "JwtVerificationError";
270
+ }
271
+ };
181
272
  var serializeAttrs = (attrs) => Object.entries(attrs).filter(([, v]) => v !== void 0).map(([k, v]) => {
182
273
  if (Array.isArray(v)) return [k, `(${v.join(", ")})`];
183
274
  if (typeof v !== "string") return [k, JSON.stringify(v)];
@@ -232,21 +323,6 @@ ${formattedError}`;
232
323
  }
233
324
  };
234
325
 
235
- // src/fetcher.ts
236
- var hasStatusOrThrow = (status, customError) => async (res) => {
237
- if (Array.isArray(status) ? !status.includes(res.status) : res.status !== status) {
238
- const ErrorClass = customError ?? UnexpectedStatusCodeError;
239
- throw new ErrorClass({
240
- message: `Http request failed. Expected ${status}, got ${res.status}, url: ${res.url}`,
241
- reason: await parseRawHttpResponse(res),
242
- // Pass the response body as reason so the original error can surface
243
- statusCode: res.status
244
- });
245
- }
246
- return res;
247
- };
248
- var parseRawHttpResponse = (response) => response.headers.get("content-type")?.includes("application/json") ? response.json() : response.text();
249
-
250
326
  // src/parse.ts
251
327
  var SAFE_STRINGIFY_MAX_LENGTH = 200;
252
328
  function safeStringify(value) {
@@ -263,6 +339,26 @@ function safeStringify(value) {
263
339
  return "[unserializable]";
264
340
  }
265
341
  }
342
+ function stringToJsonWithErrorHandling(value, errorMessage) {
343
+ try {
344
+ return JSON.parse(value);
345
+ } catch {
346
+ throw new JsonParseError(
347
+ errorMessage ?? "Unable to parse string to JSON.",
348
+ value
349
+ );
350
+ }
351
+ }
352
+ function parseIfJson(data) {
353
+ if (typeof data !== "string") {
354
+ return data;
355
+ }
356
+ try {
357
+ return JSON.parse(data);
358
+ } catch {
359
+ return data;
360
+ }
361
+ }
266
362
  function parseWithErrorHandling(schema, data, customErrorMessage) {
267
363
  const parseResult = schema.safeParse(data);
268
364
  if (!parseResult.success) {
@@ -277,9 +373,522 @@ function formatError(message, prefix) {
277
373
  return prefix ? `${prefix} ${message}` : message;
278
374
  }
279
375
 
280
- // src/validation.ts
376
+ // src/crypto/jwk/z-jwk.ts
377
+ var import_zod2 = __toESM(require("zod"));
378
+
379
+ // src/crypto/z-common.ts
281
380
  var import_zod = __toESM(require("zod"));
282
- var zItwSupportedSignatureAlg = import_zod.default.enum([
381
+ var zTrustChain = import_zod.default.tuple([import_zod.default.string()], import_zod.default.string());
382
+ var zCertificateChain = import_zod.default.array(import_zod.default.string()).nonempty();
383
+ var zAlgValueNotNone = import_zod.default.string().refine((alg) => alg !== "none", { message: `alg value may not be 'none'` });
384
+
385
+ // src/crypto/jwk/z-jwk.ts
386
+ var zJwk = import_zod2.default.looseObject({
387
+ alg: import_zod2.default.optional(import_zod2.default.string()),
388
+ crv: import_zod2.default.optional(import_zod2.default.string()),
389
+ d: import_zod2.default.optional(import_zod2.default.string()),
390
+ dp: import_zod2.default.optional(import_zod2.default.string()),
391
+ dq: import_zod2.default.optional(import_zod2.default.string()),
392
+ e: import_zod2.default.optional(import_zod2.default.string()),
393
+ ext: import_zod2.default.optional(import_zod2.default.boolean()),
394
+ k: import_zod2.default.optional(import_zod2.default.string()),
395
+ key_ops: import_zod2.default.optional(import_zod2.default.array(import_zod2.default.string())),
396
+ kid: import_zod2.default.optional(import_zod2.default.string()),
397
+ kty: import_zod2.default.string(),
398
+ n: import_zod2.default.optional(import_zod2.default.string()),
399
+ oth: import_zod2.default.optional(
400
+ import_zod2.default.array(
401
+ import_zod2.default.looseObject({
402
+ d: import_zod2.default.optional(import_zod2.default.string()),
403
+ r: import_zod2.default.optional(import_zod2.default.string()),
404
+ t: import_zod2.default.optional(import_zod2.default.string())
405
+ })
406
+ )
407
+ ),
408
+ p: import_zod2.default.optional(import_zod2.default.string()),
409
+ q: import_zod2.default.optional(import_zod2.default.string()),
410
+ qi: import_zod2.default.optional(import_zod2.default.string()),
411
+ use: import_zod2.default.optional(import_zod2.default.string()),
412
+ x: import_zod2.default.optional(import_zod2.default.string()),
413
+ x5c: import_zod2.default.optional(zCertificateChain),
414
+ x5t: import_zod2.default.optional(import_zod2.default.string()),
415
+ "x5t#S256": import_zod2.default.optional(import_zod2.default.string()),
416
+ x5u: import_zod2.default.optional(import_zod2.default.string()),
417
+ y: import_zod2.default.optional(import_zod2.default.string())
418
+ });
419
+ var zJwkSet = import_zod2.default.looseObject({ keys: import_zod2.default.array(zJwk) });
420
+
421
+ // src/crypto/jwk/calculate-jwk-thumbprint.ts
422
+ function createJwkThumbprintComponents(jwk) {
423
+ if (jwk.kty === "EC") {
424
+ if (!jwk.crv || !jwk.x || !jwk.y) {
425
+ throw new ValidationError(
426
+ "Provided jwk does not match a supported jwk structure. Either the 'kty' is not supported, or required values are missing."
427
+ );
428
+ }
429
+ return {
430
+ crv: jwk.crv,
431
+ kty: jwk.kty,
432
+ x: jwk.x,
433
+ y: jwk.y
434
+ };
435
+ }
436
+ if (jwk.kty === "RSA") {
437
+ if (!jwk.e || !jwk.n) {
438
+ throw new ValidationError(
439
+ "Provided jwk does not match a supported jwk structure. Either the 'kty' is not supported, or required values are missing."
440
+ );
441
+ }
442
+ return {
443
+ e: jwk.e,
444
+ kty: jwk.kty,
445
+ n: jwk.n
446
+ };
447
+ }
448
+ if (jwk.kty === "oct") {
449
+ if (!jwk.k) {
450
+ throw new ValidationError(
451
+ "Provided jwk does not match a supported jwk structure. Either the 'kty' is not supported, or required values are missing."
452
+ );
453
+ }
454
+ return {
455
+ k: jwk.k,
456
+ kty: jwk.kty
457
+ };
458
+ }
459
+ throw new ValidationError(
460
+ "Provided jwk does not match a supported jwk structure. Either the 'kty' is not supported, or required values are missing."
461
+ );
462
+ }
463
+ async function calculateJwkThumbprint(options) {
464
+ const parsedJwk = parseWithErrorHandling(
465
+ zJwk,
466
+ options.jwk,
467
+ "Provided jwk does not match a supported jwk structure. Either the 'kty' is not supported, or required values are missing."
468
+ );
469
+ const jwkThumbprintComponents = createJwkThumbprintComponents(parsedJwk);
470
+ return encodeToBase64Url(
471
+ await options.hashCallback(
472
+ decodeUtf8String(JSON.stringify(jwkThumbprintComponents)),
473
+ options.hashAlgorithm
474
+ )
475
+ );
476
+ }
477
+
478
+ // src/crypto/jwt/z-jwt.ts
479
+ var import_zod3 = __toESM(require("zod"));
480
+ var MAX_JTI_LENGTH = 256;
481
+ var zCompactJwt = import_zod3.default.string().regex(/^([a-zA-Z0-9-_]+)\.([a-zA-Z0-9-_]+)\.([a-zA-Z0-9-_]+)$/, {
482
+ message: "Not a valid compact jwt"
483
+ });
484
+ var zJwtConfirmationPayload = import_zod3.default.looseObject({
485
+ // RFC9449. jwk thumbprint of the dpop public key to which the access token is bound
486
+ jkt: import_zod3.default.string().optional(),
487
+ jwk: zJwk.optional()
488
+ });
489
+ var zJwtPayload = import_zod3.default.looseObject({
490
+ aud: import_zod3.default.string().or(import_zod3.default.array(import_zod3.default.string())).optional(),
491
+ cnf: zJwtConfirmationPayload.optional(),
492
+ exp: import_zod3.default.number().int().optional(),
493
+ iat: import_zod3.default.number().int().optional(),
494
+ iss: import_zod3.default.string().optional(),
495
+ jti: import_zod3.default.string().max(MAX_JTI_LENGTH).optional(),
496
+ nbf: import_zod3.default.number().int().optional(),
497
+ nonce: import_zod3.default.string().optional(),
498
+ // Reserved for status parameters
499
+ status: import_zod3.default.record(import_zod3.default.string(), import_zod3.default.any()).optional(),
500
+ sub: import_zod3.default.string().optional(),
501
+ // Reserved for OpenID Federation
502
+ trust_chain: zTrustChain.optional()
503
+ });
504
+ var zJwtHeader = import_zod3.default.looseObject({
505
+ alg: zAlgValueNotNone,
506
+ jwk: zJwk.optional(),
507
+ kid: import_zod3.default.string().optional(),
508
+ // Reserved for OpenID Federation
509
+ trust_chain: zTrustChain.optional(),
510
+ typ: import_zod3.default.string().optional(),
511
+ x5c: zCertificateChain.optional()
512
+ });
513
+
514
+ // src/crypto/jwt/decode-jwt-header.ts
515
+ function decodeJwtHeader(options) {
516
+ const jwtParts = options.jwt.split(".");
517
+ if (jwtParts.length <= 2) {
518
+ throw new JwtParseError(
519
+ formatError(
520
+ "Unable to decode because Jwt is not a valid!",
521
+ options.errorMessagePrefix
522
+ )
523
+ );
524
+ }
525
+ const [headerPart] = jwtParts;
526
+ let headerJson;
527
+ try {
528
+ headerJson = stringToJsonWithErrorHandling(
529
+ encodeToUtf8String(decodeBase64(headerPart)),
530
+ formatError(
531
+ "Unable to parse jwt header to JSON",
532
+ options.errorMessagePrefix
533
+ )
534
+ );
535
+ } catch (error) {
536
+ throw new JwtParseError(
537
+ formatError(
538
+ `Error parsing JWT. ${error instanceof Error ? error.message : ""}`,
539
+ options.errorMessagePrefix
540
+ )
541
+ );
542
+ }
543
+ const header = parseWithErrorHandling(
544
+ options.headerSchema ?? zJwtHeader,
545
+ headerJson,
546
+ formatError("Invalid JWT header", options.errorMessagePrefix)
547
+ );
548
+ return {
549
+ header
550
+ };
551
+ }
552
+ function jwtHeaderFromJwtSigner(signer) {
553
+ if (signer.method === "did") {
554
+ return {
555
+ alg: signer.alg,
556
+ kid: signer.didUrl
557
+ };
558
+ }
559
+ if (signer.method === "federation") {
560
+ return {
561
+ alg: signer.alg,
562
+ kid: signer.kid,
563
+ trust_chain: signer.trustChain
564
+ };
565
+ }
566
+ if (signer.method === "jwk") {
567
+ return {
568
+ alg: signer.alg,
569
+ jwk: signer.publicJwk
570
+ };
571
+ }
572
+ if (signer.method === "x5c") {
573
+ return {
574
+ alg: signer.alg,
575
+ kid: signer.kid,
576
+ trust_chain: signer.trustChain,
577
+ x5c: signer.x5c
578
+ };
579
+ }
580
+ return { alg: signer.alg };
581
+ }
582
+ function jwtSignerFromJwt(options) {
583
+ const { allowedSignerMethods, header, payload } = options;
584
+ const found = [];
585
+ if (header.x5c) {
586
+ found.push({
587
+ method: "x5c",
588
+ signer: {
589
+ alg: header.alg,
590
+ kid: header.kid,
591
+ method: "x5c",
592
+ trustChain: header.trust_chain,
593
+ x5c: header.x5c
594
+ },
595
+ valid: true
596
+ });
597
+ }
598
+ if (header.trust_chain) {
599
+ if (!header.kid) {
600
+ found.push({
601
+ error: "When 'trust_chain' is used in jwt header, the 'kid' parameter is required.",
602
+ method: "federation",
603
+ valid: false
604
+ });
605
+ } else {
606
+ found.push({
607
+ method: "federation",
608
+ signer: {
609
+ alg: header.alg,
610
+ kid: header.kid,
611
+ method: "federation",
612
+ trustChain: header.trust_chain
613
+ },
614
+ valid: true
615
+ });
616
+ }
617
+ }
618
+ if (header.kid?.startsWith("did:") || payload.iss?.startsWith("did:")) {
619
+ if (payload.iss && header.kid?.startsWith("did:") && !header.kid.startsWith(payload.iss)) {
620
+ found.push({
621
+ error: "kid in header starts with did that is different from did value in 'iss'",
622
+ method: "did",
623
+ valid: false
624
+ });
625
+ } else if (!header.kid?.startsWith("did:") && !header.kid?.startsWith("#")) {
626
+ found.push({
627
+ error: "kid in header must start with either 'did:' or '#' when 'iss' value is a did",
628
+ method: "did",
629
+ valid: false
630
+ });
631
+ } else if (header.kid) {
632
+ found.push({
633
+ method: "did",
634
+ signer: {
635
+ alg: header.alg,
636
+ didUrl: header.kid.startsWith("did:") ? header.kid : `${payload.iss}${header.kid}`,
637
+ method: "did"
638
+ },
639
+ valid: true
640
+ });
641
+ }
642
+ }
643
+ if (header.jwk) {
644
+ found.push({
645
+ method: "jwk",
646
+ signer: {
647
+ alg: header.alg,
648
+ method: "jwk",
649
+ publicJwk: header.jwk
650
+ },
651
+ valid: true
652
+ });
653
+ }
654
+ const allowedFoundMethods = found.filter(
655
+ (candidate) => !allowedSignerMethods || allowedSignerMethods.includes(candidate.method)
656
+ );
657
+ const allowedValidMethods = allowedFoundMethods.filter(
658
+ (candidate) => candidate.valid
659
+ );
660
+ const firstAllowedValidMethod = allowedValidMethods[0];
661
+ if (firstAllowedValidMethod && firstAllowedValidMethod.valid) {
662
+ return firstAllowedValidMethod.signer;
663
+ }
664
+ if (allowedFoundMethods.length > 0) {
665
+ throw new JwtParseError(
666
+ `Unable to extract signer method from jwt. Found ${allowedFoundMethods.length} allowed signer method(s) but contained invalid configuration:
667
+ ${allowedFoundMethods.map(
668
+ (candidate) => candidate.valid ? "" : `FAILED: method ${candidate.method} - ${candidate.error}`
669
+ ).join("\n")}`
670
+ );
671
+ }
672
+ if (found.length > 0) {
673
+ throw new JwtParseError(
674
+ `Unable to extract signer method from jwt. Found ${found.length} signer method(s) that are not allowed:
675
+ ${found.map(
676
+ (candidate) => candidate.valid ? `SUCCEEDED: method ${candidate.method}` : `FAILED: method ${candidate.method} - ${candidate.error}`
677
+ ).join("\n")}`
678
+ );
679
+ }
680
+ if (!allowedSignerMethods || allowedSignerMethods.includes("custom")) {
681
+ return {
682
+ alg: header.alg,
683
+ kid: header.kid,
684
+ method: "custom"
685
+ };
686
+ }
687
+ throw new JwtParseError(
688
+ "Unable to extract signer method from jwt. Found no signer methods and 'custom' signer method is not allowed."
689
+ );
690
+ }
691
+
692
+ // src/crypto/jwt/decode-jwt.ts
693
+ function decodeJwt(options) {
694
+ const jwtParts = options.jwt.split(".");
695
+ if (jwtParts.length !== 3) {
696
+ throw new JwtParseError(
697
+ formatError(
698
+ "Unable to decode because Jwt is not a valid!",
699
+ options.errorMessagePrefix
700
+ )
701
+ );
702
+ }
703
+ let payloadJson;
704
+ try {
705
+ const payloadPart = jwtParts[1];
706
+ if (payloadPart === void 0) {
707
+ throw new JwtParseError(
708
+ formatError(
709
+ "Unable to decode because Jwt is not a valid!",
710
+ options.errorMessagePrefix
711
+ )
712
+ );
713
+ }
714
+ payloadJson = stringToJsonWithErrorHandling(
715
+ encodeToUtf8String(decodeBase64(payloadPart)),
716
+ formatError(
717
+ "Unable to parse jwt payload to JSON",
718
+ options.errorMessagePrefix
719
+ )
720
+ );
721
+ } catch (error) {
722
+ throw new JwtParseError(
723
+ formatError(
724
+ `Error parsing JWT. ${error instanceof Error ? error.message : ""}`,
725
+ options.errorMessagePrefix
726
+ )
727
+ );
728
+ }
729
+ const signaturePart = jwtParts[2];
730
+ if (signaturePart === void 0) {
731
+ throw new JwtParseError(
732
+ formatError(
733
+ "Unable to decode because Jwt is not a valid!",
734
+ options.errorMessagePrefix
735
+ )
736
+ );
737
+ }
738
+ const { header } = decodeJwtHeader({
739
+ errorMessagePrefix: options.errorMessagePrefix,
740
+ headerSchema: options.headerSchema,
741
+ jwt: options.jwt
742
+ });
743
+ const payload = parseWithErrorHandling(
744
+ options.payloadSchema ?? zJwtPayload,
745
+ payloadJson,
746
+ formatError("Invalid JWT payload", options.errorMessagePrefix)
747
+ );
748
+ return {
749
+ compact: options.jwt,
750
+ header,
751
+ payload,
752
+ signature: signaturePart
753
+ };
754
+ }
755
+
756
+ // src/date.ts
757
+ function dateToSeconds(date) {
758
+ const milliseconds = date?.getTime() ?? Date.now();
759
+ return Math.floor(milliseconds / 1e3);
760
+ }
761
+ function addSecondsToDate(date, seconds) {
762
+ return new Date(date.getTime() + seconds * 1e3);
763
+ }
764
+
765
+ // src/crypto/jwt/verify-jwt.ts
766
+ async function verifyJwt(options) {
767
+ const errorMessage = options.errorMessage ?? "Error during verification of jwt.";
768
+ let signerJwk;
769
+ try {
770
+ const result = await options.verifyJwtCallback(options.signer, {
771
+ compact: options.compact,
772
+ header: options.header,
773
+ payload: options.payload
774
+ });
775
+ if (!result.verified) {
776
+ throw new JwtVerificationError(errorMessage);
777
+ }
778
+ signerJwk = result.signerJwk;
779
+ } catch (error) {
780
+ if (error instanceof JwtVerificationError) {
781
+ throw error;
782
+ }
783
+ throw new JwtVerificationError(errorMessage, { cause: error });
784
+ }
785
+ const nowInSeconds = dateToSeconds(options.now ?? /* @__PURE__ */ new Date());
786
+ const skewInSeconds = options.allowedSkewInSeconds ?? 0;
787
+ const timeBasedValidation = options.skipTimeBasedValidation !== void 0 ? !options.skipTimeBasedValidation : true;
788
+ if (timeBasedValidation && options.payload.nbf && nowInSeconds < options.payload.nbf - skewInSeconds) {
789
+ throw new JwtVerificationError(
790
+ `${errorMessage} jwt 'nbf' is in the future`
791
+ );
792
+ }
793
+ if (timeBasedValidation && options.payload.exp && nowInSeconds > options.payload.exp + skewInSeconds) {
794
+ throw new JwtVerificationError(`${errorMessage} jwt 'exp' is in the past`);
795
+ }
796
+ if (options.expectedAudience) {
797
+ const { aud } = options.payload;
798
+ if (Array.isArray(aud) && !aud.includes(options.expectedAudience) || typeof aud === "string" && aud !== options.expectedAudience) {
799
+ throw new JwtVerificationError(
800
+ `${errorMessage} jwt 'aud' does not match expected value.`
801
+ );
802
+ }
803
+ }
804
+ if (options.expectedIssuer && options.expectedIssuer !== options.payload.iss) {
805
+ throw new JwtVerificationError(
806
+ `${errorMessage} jwt 'iss' does not match expected value.`
807
+ );
808
+ }
809
+ if (options.expectedNonce && options.expectedNonce !== options.payload.nonce) {
810
+ throw new JwtVerificationError(
811
+ `${errorMessage} jwt 'nonce' does not match expected value.`
812
+ );
813
+ }
814
+ if (options.expectedSubject && options.expectedSubject !== options.payload.sub) {
815
+ throw new JwtVerificationError(
816
+ `${errorMessage} jwt 'sub' does not match expected value.`
817
+ );
818
+ }
819
+ if (options.requiredClaims) {
820
+ for (const claim of options.requiredClaims) {
821
+ if (!options.payload[claim]) {
822
+ throw new JwtVerificationError(
823
+ `${errorMessage} jwt '${claim}' is missing.`
824
+ );
825
+ }
826
+ }
827
+ }
828
+ return {
829
+ signer: {
830
+ ...options.signer,
831
+ publicJwk: signerJwk
832
+ }
833
+ };
834
+ }
835
+
836
+ // src/crypto/jwt/z-jwe.ts
837
+ var import_zod4 = require("zod");
838
+ var zCompactJwe = import_zod4.z.string().regex(
839
+ /^[A-Za-z0-9_-]+\.[A-Za-z0-9_-]*\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+$/,
840
+ {
841
+ message: "Not a valid compact jwe"
842
+ }
843
+ );
844
+
845
+ // src/fetcher.ts
846
+ var defaultFetcher = fetch;
847
+ function createFetcher(fetcher = defaultFetcher) {
848
+ return (input, init) => fetcher(
849
+ input,
850
+ init ? {
851
+ ...init,
852
+ body: init.body instanceof URLSearchParams ? init.body.toString() : init.body
853
+ } : void 0
854
+ ).catch((error) => {
855
+ throw new Error(
856
+ `Unknown error occurred during fetch to '${String(input)}'
857
+ Cause: ${error instanceof Error ? error.message : String(error)}`
858
+ );
859
+ });
860
+ }
861
+ var hasStatusOrThrow = (status, customError) => async (res) => {
862
+ if (Array.isArray(status) ? !status.includes(res.status) : res.status !== status) {
863
+ const ErrorClass = customError ?? UnexpectedStatusCodeError;
864
+ throw new ErrorClass({
865
+ message: `Http request failed. Expected ${status}, got ${res.status}, url: ${res.url}`,
866
+ reason: await parseRawHttpResponse(res),
867
+ // Pass the response body as reason so the original error can surface
868
+ statusCode: res.status
869
+ });
870
+ }
871
+ return res;
872
+ };
873
+ var parseRawHttpResponse = (response) => response.headers.get("content-type")?.includes("application/json") ? response.json() : response.text();
874
+
875
+ // src/url.ts
876
+ function objectToQueryParams(object) {
877
+ const params = new URLSearchParams();
878
+ for (const [key, value] of Object.entries(object)) {
879
+ if (value != null) {
880
+ params.append(
881
+ key,
882
+ typeof value === "object" ? JSON.stringify(value) : String(value)
883
+ );
884
+ }
885
+ }
886
+ return params;
887
+ }
888
+
889
+ // src/validation.ts
890
+ var import_zod5 = __toESM(require("zod"));
891
+ var zItwSupportedSignatureAlg = import_zod5.default.enum([
283
892
  "ES256",
284
893
  "ES384",
285
894
  "ES512",
@@ -287,7 +896,7 @@ var zItwSupportedSignatureAlg = import_zod.default.enum([
287
896
  "PS384",
288
897
  "PS512"
289
898
  ]);
290
- var zHttpMethod = import_zod.default.enum([
899
+ var zHttpMethod = import_zod5.default.enum([
291
900
  "GET",
292
901
  "POST",
293
902
  "PUT",
@@ -337,10 +946,6 @@ function dispatchByVersion(version, handlers) {
337
946
  }
338
947
  return handler();
339
948
  }
340
-
341
- // src/index.ts
342
- var import_oauth2 = require("@openid4vc/oauth2");
343
- var import_utils = require("@openid4vc/utils");
344
949
  // Annotate the CommonJS export names for ESM import in node:
345
950
  0 && (module.exports = {
346
951
  CLOCK_SKEW_TOLERANCE_SECONDS,
@@ -352,7 +957,10 @@ var import_utils = require("@openid4vc/utils");
352
957
  ItWalletSpecsVersion,
353
958
  ItWalletSpecsVersionError,
354
959
  JsonParseError,
960
+ JwtParseError,
961
+ JwtVerificationError,
355
962
  MAX_IAT_AGE_SECONDS,
963
+ MAX_JTI_LENGTH,
356
964
  UnexpectedStatusCodeError,
357
965
  ValidationError,
358
966
  addSecondsToDate,
@@ -362,6 +970,7 @@ var import_utils = require("@openid4vc/utils");
362
970
  dateToSeconds,
363
971
  decodeBase64,
364
972
  decodeJwt,
973
+ decodeJwtHeader,
365
974
  decodeUtf8String,
366
975
  dispatchByVersion,
367
976
  encodeToBase64Url,
@@ -370,15 +979,27 @@ var import_utils = require("@openid4vc/utils");
370
979
  formatZodError,
371
980
  hasConfigVersion,
372
981
  hasStatusOrThrow,
982
+ jwtHeaderFromJwtSigner,
983
+ jwtSignerFromJwt,
373
984
  objectToQueryParams,
374
985
  parseIfJson,
375
986
  parseRawHttpResponse,
376
987
  parseWithErrorHandling,
377
988
  serializeAttrs,
378
- setGlobalConfig,
379
989
  stringToJsonWithErrorHandling,
990
+ verifyJwt,
380
991
  verifyJwtIatOrThrow,
992
+ zAlgValueNotNone,
993
+ zCertificateChain,
994
+ zCompactJwe,
995
+ zCompactJwt,
381
996
  zHttpMethod,
382
- zItwSupportedSignatureAlg
997
+ zItwSupportedSignatureAlg,
998
+ zJwk,
999
+ zJwkSet,
1000
+ zJwtConfirmationPayload,
1001
+ zJwtHeader,
1002
+ zJwtPayload,
1003
+ zTrustChain
383
1004
  });
384
1005
  //# sourceMappingURL=index.js.map