@pagopa/io-wallet-oid4vci 1.4.2 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -196,7 +196,12 @@ async function sendAuthorizationResponseAndExtractCode(options) {
196
196
  }
197
197
 
198
198
  // src/credential-offer/extract-grant-details.ts
199
- function extractGrantDetails(credentialOffer) {
199
+ import {
200
+ ItWalletSpecsVersion,
201
+ ItWalletSpecsVersionError,
202
+ createVersionDispatcher
203
+ } from "@pagopa/io-wallet-utils";
204
+ function requireAuthorizationCodeGrant(credentialOffer) {
200
205
  if (!credentialOffer.grants) {
201
206
  throw new CredentialOfferError("No grants found in credential offer");
202
207
  }
@@ -204,6 +209,10 @@ function extractGrantDetails(credentialOffer) {
204
209
  if (!authCodeGrant) {
205
210
  throw new CredentialOfferError("authorization_code grant not found");
206
211
  }
212
+ return authCodeGrant;
213
+ }
214
+ function extractGrantDetailsV1_3(options) {
215
+ const authCodeGrant = requireAuthorizationCodeGrant(options.credentialOffer);
207
216
  return {
208
217
  authorizationCodeGrant: {
209
218
  authorizationServer: authCodeGrant.authorization_server,
@@ -213,10 +222,37 @@ function extractGrantDetails(credentialOffer) {
213
222
  grantType: "authorization_code"
214
223
  };
215
224
  }
225
+ function extractGrantDetailsV1_4(options) {
226
+ const authCodeGrant = requireAuthorizationCodeGrant(options.credentialOffer);
227
+ return {
228
+ authorizationCodeGrant: {
229
+ authorizationServer: authCodeGrant.authorization_server,
230
+ issuerState: authCodeGrant.issuer_state
231
+ },
232
+ grantType: "authorization_code"
233
+ };
234
+ }
235
+ var dispatchExtractGrantDetails = createVersionDispatcher({
236
+ [ItWalletSpecsVersion.V1_0]: () => {
237
+ throw new ItWalletSpecsVersionError(
238
+ "extractGrantDetails",
239
+ ItWalletSpecsVersion.V1_0,
240
+ [ItWalletSpecsVersion.V1_3, ItWalletSpecsVersion.V1_4]
241
+ );
242
+ },
243
+ [ItWalletSpecsVersion.V1_3]: (o) => extractGrantDetailsV1_3(o),
244
+ [ItWalletSpecsVersion.V1_4]: (o) => extractGrantDetailsV1_4(o)
245
+ });
246
+ function extractGrantDetails(options) {
247
+ return dispatchExtractGrantDetails(options);
248
+ }
216
249
 
217
250
  // src/credential-offer/z-credential-offer.ts
251
+ import { z as z4 } from "zod";
252
+
253
+ // src/credential-offer/v1.3/z-credential-offer.ts
218
254
  import { z as z2 } from "zod";
219
- var zAuthorizationCodeGrant = z2.object({
255
+ var zAuthorizationCodeGrantV1_3 = z2.object({
220
256
  /**
221
257
  * CONDITIONALLY REQUIRED. HTTPS URL of the Authorization Server.
222
258
  * REQUIRED only when the Credential Issuer uses multiple Authorization Servers.
@@ -234,14 +270,14 @@ var zAuthorizationCodeGrant = z2.object({
234
270
  */
235
271
  scope: z2.string()
236
272
  });
237
- var zCredentialOfferGrants = z2.object({
273
+ var zCredentialOfferGrantsV1_3 = z2.object({
238
274
  /**
239
275
  * REQUIRED. Authorization Code grant details.
240
276
  * IT-Wallet v1.3 only supports authorization_code grant.
241
277
  */
242
- authorization_code: zAuthorizationCodeGrant
278
+ authorization_code: zAuthorizationCodeGrantV1_3
243
279
  });
244
- var zCredentialOffer = z2.object({
280
+ var zCredentialOfferV1_3 = z2.object({
245
281
  /**
246
282
  * REQUIRED. Array of credential configuration identifiers.
247
283
  * References the types of credentials offered as defined in the Credential Issuer metadata.
@@ -256,24 +292,66 @@ var zCredentialOffer = z2.object({
256
292
  * REQUIRED. Grant information for the credential offer.
257
293
  * IT-Wallet v1.3 requires authorization_code grant.
258
294
  */
259
- grants: zCredentialOfferGrants
295
+ grants: zCredentialOfferGrantsV1_3
296
+ });
297
+
298
+ // src/credential-offer/v1.4/z-credential-offer.ts
299
+ import { z as z3 } from "zod";
300
+ var zAuthorizationCodeGrantV1_4 = z3.object({
301
+ /**
302
+ * CONDITIONALLY REQUIRED. HTTPS URL of the Authorization Server.
303
+ * REQUIRED only when the Credential Issuer uses multiple Authorization Servers.
304
+ * If present, MUST match one of the authorization_servers in the Credential Issuer metadata.
305
+ */
306
+ authorization_server: z3.url().optional(),
307
+ /**
308
+ * OPTIONAL. String value representing the issuer state.
309
+ * Used to correlate the authorization request with the credential offer.
310
+ */
311
+ issuer_state: z3.string().optional()
260
312
  });
261
- var zCredentialOfferUri = z2.object({
313
+ var zCredentialOfferGrantsV1_4 = z3.object({
314
+ /**
315
+ * REQUIRED. Authorization Code grant details.
316
+ * IT-Wallet v1.4 only supports authorization_code grant.
317
+ */
318
+ authorization_code: zAuthorizationCodeGrantV1_4
319
+ });
320
+ var zCredentialOfferV1_4 = z3.object({
321
+ /**
322
+ * REQUIRED. Array of credential configuration identifiers.
323
+ * References the types of credentials offered as defined in the Credential Issuer metadata.
324
+ */
325
+ credential_configuration_ids: z3.array(z3.string()).min(1),
326
+ /**
327
+ * REQUIRED. HTTPS URL of the Credential Issuer.
328
+ * The Credential Issuer from which the wallet will request credentials.
329
+ */
330
+ credential_issuer: z3.url(),
331
+ /**
332
+ * REQUIRED. Grant information for the credential offer.
333
+ * IT-Wallet v1.4 requires authorization_code grant.
334
+ */
335
+ grants: zCredentialOfferGrantsV1_4
336
+ });
337
+
338
+ // src/credential-offer/z-credential-offer.ts
339
+ var zCredentialOfferUri = z4.object({
262
340
  /**
263
341
  * OPTIONAL. Inline credential offer JSON (by value).
264
342
  * URL-encoded JSON string containing the credential offer.
265
343
  */
266
- credential_offer: z2.string().optional(),
344
+ credential_offer: z4.string().optional(),
267
345
  /**
268
346
  * OPTIONAL. URL pointing to the credential offer JSON (by reference).
269
347
  * HTTPS URL where the credential offer can be fetched.
270
348
  */
271
- credential_offer_uri: z2.url().optional(),
349
+ credential_offer_uri: z4.url().optional(),
272
350
  /**
273
351
  * URL scheme used for the credential offer.
274
352
  * Determines the invocation method.
275
353
  */
276
- scheme: z2.enum(["openid-credential-offer", "haip-vci", "https"])
354
+ scheme: z4.enum(["openid-credential-offer", "haip-vci", "https"])
277
355
  }).refine((data) => data.credential_offer || data.credential_offer_uri, {
278
356
  message: "Either credential_offer or credential_offer_uri must be present"
279
357
  });
@@ -312,19 +390,35 @@ async function parseCredentialOfferUri(options) {
312
390
 
313
391
  // src/credential-offer/resolve-credential-offer.ts
314
392
  import {
393
+ ItWalletSpecsVersion as ItWalletSpecsVersion2,
394
+ ItWalletSpecsVersionError as ItWalletSpecsVersionError2,
315
395
  UnexpectedStatusCodeError as UnexpectedStatusCodeError2,
316
396
  createFetcher as createFetcher2,
317
397
  hasStatusOrThrow as hasStatusOrThrow2
318
398
  } from "@pagopa/io-wallet-utils";
399
+ function parseCredentialOfferForVersion(config, data) {
400
+ switch (config.itWalletSpecsVersion) {
401
+ case ItWalletSpecsVersion2.V1_3:
402
+ return zCredentialOfferV1_3.parse(data);
403
+ case ItWalletSpecsVersion2.V1_4:
404
+ return zCredentialOfferV1_4.parse(data);
405
+ default:
406
+ throw new ItWalletSpecsVersionError2(
407
+ "resolveCredentialOffer",
408
+ config.itWalletSpecsVersion,
409
+ [ItWalletSpecsVersion2.V1_3, ItWalletSpecsVersion2.V1_4]
410
+ );
411
+ }
412
+ }
319
413
  async function resolveCredentialOffer(options) {
320
- const { callbacks, credentialOffer } = options;
414
+ const { callbacks, config, credentialOffer } = options;
321
415
  try {
322
416
  if (credentialOffer.startsWith("openid-credential-offer://") || credentialOffer.startsWith("haip-vci://") || credentialOffer.startsWith("https://")) {
323
417
  const parsed = await parseCredentialOfferUri({ uri: credentialOffer });
324
418
  if (parsed.credential_offer) {
325
419
  const decoded = decodeURIComponent(parsed.credential_offer);
326
420
  const offerJson2 = JSON.parse(decoded);
327
- return zCredentialOffer.parse(offerJson2);
421
+ return parseCredentialOfferForVersion(config, offerJson2);
328
422
  }
329
423
  if (parsed.credential_offer_uri) {
330
424
  const fetch = createFetcher2(callbacks.fetch);
@@ -336,13 +430,13 @@ async function resolveCredentialOffer(options) {
336
430
  });
337
431
  await hasStatusOrThrow2(200, UnexpectedStatusCodeError2)(response);
338
432
  const offerJson2 = await response.json();
339
- return zCredentialOffer.parse(offerJson2);
433
+ return parseCredentialOfferForVersion(config, offerJson2);
340
434
  }
341
435
  }
342
436
  const offerJson = JSON.parse(credentialOffer);
343
- return zCredentialOffer.parse(offerJson);
437
+ return parseCredentialOfferForVersion(config, offerJson);
344
438
  } catch (error) {
345
- if (error instanceof CredentialOfferError || error instanceof UnexpectedStatusCodeError2) {
439
+ if (error instanceof CredentialOfferError || error instanceof UnexpectedStatusCodeError2 || error instanceof ItWalletSpecsVersionError2) {
346
440
  throw error;
347
441
  }
348
442
  throw new CredentialOfferError(
@@ -352,8 +446,38 @@ async function resolveCredentialOffer(options) {
352
446
  }
353
447
 
354
448
  // src/credential-offer/validate-credential-offer.ts
355
- async function validateCredentialOffer(options) {
356
- const { credentialIssuerMetadata, credentialOffer } = options;
449
+ import {
450
+ ItWalletSpecsVersion as ItWalletSpecsVersion3,
451
+ ItWalletSpecsVersionError as ItWalletSpecsVersionError3,
452
+ createVersionDispatcher as createVersionDispatcher2
453
+ } from "@pagopa/io-wallet-utils";
454
+ function assertAuthorizationServerAllowed(authorizationServer, authorizationServers) {
455
+ if (!authorizationServer) {
456
+ if (authorizationServers && authorizationServers.length > 1) {
457
+ throw new CredentialOfferError(
458
+ "authorization_server is REQUIRED when Credential Issuer uses multiple Authorization Servers"
459
+ );
460
+ }
461
+ return;
462
+ }
463
+ if (!authorizationServers) {
464
+ throw new CredentialOfferError(
465
+ "credential offer specified an `authorization_server` but issuer metadata doesn't contain `authorization_servers`"
466
+ );
467
+ }
468
+ if (authorizationServers.length === 1) {
469
+ throw new CredentialOfferError(
470
+ "credential offer specified an `authorization_server` but issuer metadata's `authorization_servers` contains only an element"
471
+ );
472
+ }
473
+ if (!authorizationServers.includes(authorizationServer)) {
474
+ throw new CredentialOfferError(
475
+ `authorization_server '${authorizationServer}' does not match Credential Issuer metadata. Valid servers: ${authorizationServers.join(", ")}`
476
+ );
477
+ }
478
+ }
479
+ function validateBaseCredentialOffer(options) {
480
+ const { credentialIssuerMetadata, credentialOffer, versionLabel } = options;
357
481
  if (!credentialOffer.credential_issuer.startsWith("https://")) {
358
482
  throw new CredentialOfferError("credential_issuer must be an HTTPS URL");
359
483
  }
@@ -363,38 +487,57 @@ async function validateCredentialOffer(options) {
363
487
  );
364
488
  }
365
489
  if (!credentialOffer.grants) {
366
- throw new CredentialOfferError("grants is REQUIRED for IT-Wallet v1.3");
490
+ throw new CredentialOfferError(
491
+ `grants is REQUIRED for IT-Wallet ${versionLabel}`
492
+ );
367
493
  }
368
494
  const authCodeGrant = credentialOffer.grants.authorization_code;
369
495
  if (!authCodeGrant) {
370
496
  throw new CredentialOfferError(
371
- "authorization_code grant is REQUIRED for IT-Wallet v1.3"
497
+ `authorization_code grant is REQUIRED for IT-Wallet ${versionLabel}`
372
498
  );
373
499
  }
374
- if (!authCodeGrant.scope) {
500
+ assertAuthorizationServerAllowed(
501
+ authCodeGrant.authorization_server,
502
+ credentialIssuerMetadata?.authorization_servers
503
+ );
504
+ }
505
+ async function validateCredentialOfferV1_3(options) {
506
+ validateBaseCredentialOffer({
507
+ credentialIssuerMetadata: options.credentialIssuerMetadata,
508
+ credentialOffer: options.credentialOffer,
509
+ versionLabel: "v1.3"
510
+ });
511
+ if (!options.credentialOffer.grants.authorization_code.scope) {
375
512
  throw new CredentialOfferError("authorization_code.scope is REQUIRED");
376
513
  }
377
- if (credentialIssuerMetadata?.authorization_servers) {
378
- const authServers = credentialIssuerMetadata.authorization_servers;
379
- if (authServers.length > 1 && !authCodeGrant.authorization_server) {
380
- throw new CredentialOfferError(
381
- "authorization_server is REQUIRED when Credential Issuer uses multiple Authorization Servers"
382
- );
383
- }
384
- if (authCodeGrant.authorization_server) {
385
- if (!authServers.includes(authCodeGrant.authorization_server)) {
386
- throw new CredentialOfferError(
387
- `authorization_server '${authCodeGrant.authorization_server}' does not match Credential Issuer metadata. Valid servers: ${authServers.join(", ")}`
388
- );
389
- }
390
- }
391
- }
514
+ }
515
+ async function validateCredentialOfferV1_4(options) {
516
+ validateBaseCredentialOffer({
517
+ credentialIssuerMetadata: options.credentialIssuerMetadata,
518
+ credentialOffer: options.credentialOffer,
519
+ versionLabel: "v1.4"
520
+ });
521
+ }
522
+ var dispatchValidateCredentialOffer = createVersionDispatcher2({
523
+ [ItWalletSpecsVersion3.V1_0]: () => {
524
+ throw new ItWalletSpecsVersionError3(
525
+ "validateCredentialOffer",
526
+ ItWalletSpecsVersion3.V1_0,
527
+ [ItWalletSpecsVersion3.V1_3, ItWalletSpecsVersion3.V1_4]
528
+ );
529
+ },
530
+ [ItWalletSpecsVersion3.V1_3]: (o) => validateCredentialOfferV1_3(o),
531
+ [ItWalletSpecsVersion3.V1_4]: (o) => validateCredentialOfferV1_4(o)
532
+ });
533
+ async function validateCredentialOffer(options) {
534
+ return dispatchValidateCredentialOffer(options);
392
535
  }
393
536
 
394
537
  // src/credential-request/create-credential-request.ts
395
538
  import {
396
- ItWalletSpecsVersion as ItWalletSpecsVersion3,
397
- createVersionDispatcher
539
+ ItWalletSpecsVersion as ItWalletSpecsVersion6,
540
+ createVersionDispatcher as createVersionDispatcher3
398
541
  } from "@pagopa/io-wallet-utils";
399
542
 
400
543
  // src/credential-request/v1.0/create-credential-request.ts
@@ -405,18 +548,18 @@ import {
405
548
  } from "@pagopa/io-wallet-utils";
406
549
 
407
550
  // src/credential-request/v1.0/z-credential.ts
408
- import { z as z4 } from "zod";
551
+ import { z as z6 } from "zod";
409
552
 
410
553
  // src/credential-request/z-base-credential-request.ts
411
- import { z as z3 } from "zod";
412
- var zBaseCredentialRequest = z3.object({
413
- credential_configuration_id: z3.string().optional().describe(
554
+ import { z as z5 } from "zod";
555
+ var zBaseCredentialRequest = z5.object({
556
+ credential_configuration_id: z5.string().optional().describe(
414
557
  "REQUIRED if credential_identifier param is absent. MUST NOT be used otherwise."
415
558
  ),
416
- credential_identifier: z3.string().optional().describe(
559
+ credential_identifier: z5.string().optional().describe(
417
560
  "REQUIRED when Authorization Details of type openid_credential was returned. MUST NOT be used if credential_configuration_id is present."
418
561
  ),
419
- transaction_id: z3.string().optional().describe(
562
+ transaction_id: z5.string().optional().describe(
420
563
  "REQUIRED only in case of deferred flow. MUST NOT be present in immediate flow."
421
564
  )
422
565
  });
@@ -438,9 +581,9 @@ function credentialRequestRefiner(data, ctx) {
438
581
  }
439
582
 
440
583
  // src/credential-request/v1.0/z-credential.ts
441
- var zCredentialRequestProof = z4.object({
442
- jwt: z4.string().min(1, "JWT must not be empty"),
443
- proof_type: z4.literal("jwt")
584
+ var zCredentialRequestProof = z6.object({
585
+ jwt: z6.string().min(1, "JWT must not be empty"),
586
+ proof_type: z6.literal("jwt")
444
587
  // MUST be "jwt"
445
588
  });
446
589
  var zCredentialRequestV1_0 = zBaseCredentialRequest.extend({
@@ -497,10 +640,10 @@ import {
497
640
  } from "@pagopa/io-wallet-utils";
498
641
 
499
642
  // src/credential-request/v1.3/z-credential.ts
500
- import { z as z5 } from "zod";
501
- var zCredentialRequestProofJwt = z5.string().min(1, "JWT must not be empty in credential request proofs array");
502
- var zCredentialRequestProofs = z5.object({
503
- jwt: z5.tuple([zCredentialRequestProofJwt], zCredentialRequestProofJwt)
643
+ import { z as z7 } from "zod";
644
+ var zCredentialRequestProofJwt = z7.string().min(1, "JWT must not be empty in credential request proofs array");
645
+ var zCredentialRequestProofs = z7.object({
646
+ jwt: z7.tuple([zCredentialRequestProofJwt], zCredentialRequestProofJwt)
504
647
  });
505
648
  var zCredentialRequestV1_3 = zBaseCredentialRequest.extend({
506
649
  proofs: zCredentialRequestProofs.describe(
@@ -583,10 +726,10 @@ var createCredentialRequest2 = async (options) => {
583
726
  };
584
727
 
585
728
  // src/credential-request/create-credential-request.ts
586
- var dispatchCreateCredentialRequest = createVersionDispatcher({
587
- [ItWalletSpecsVersion3.V1_0]: (o) => createCredentialRequest(o),
588
- [ItWalletSpecsVersion3.V1_3]: (o) => createCredentialRequest2(o),
589
- [ItWalletSpecsVersion3.V1_4]: (o) => (
729
+ var dispatchCreateCredentialRequest = createVersionDispatcher3({
730
+ [ItWalletSpecsVersion6.V1_0]: (o) => createCredentialRequest(o),
731
+ [ItWalletSpecsVersion6.V1_3]: (o) => createCredentialRequest2(o),
732
+ [ItWalletSpecsVersion6.V1_4]: (o) => (
590
733
  // V1_4 reuses V1_3 credential request schema — no breaking changes between versions.
591
734
  // Verified against compare/1.3.3...1.4.1: credential request parameters (format, proofs, key_attestation) identical.
592
735
  createCredentialRequest2(o)
@@ -604,30 +747,32 @@ import {
604
747
  } from "@pagopa/io-wallet-oauth2";
605
748
  import {
606
749
  HEADERS,
607
- ItWalletSpecsVersion as ItWalletSpecsVersion4,
608
- ItWalletSpecsVersionError,
750
+ HashAlgorithm as HashAlgorithm2,
751
+ ItWalletSpecsVersion as ItWalletSpecsVersion7,
752
+ ItWalletSpecsVersionError as ItWalletSpecsVersionError4,
609
753
  ValidationError as ValidationError4,
610
- createVersionDispatcher as createVersionDispatcher2,
754
+ calculateJwkThumbprint as calculateJwkThumbprint2,
755
+ createVersionDispatcher as createVersionDispatcher4,
611
756
  parseWithErrorHandling as parseWithErrorHandling3
612
757
  } from "@pagopa/io-wallet-utils";
613
758
 
614
759
  // src/credential-request/z-proof-jwt.ts
615
760
  import { zJwk } from "@pagopa/io-wallet-oauth2";
616
- import { z as z6 } from "zod";
617
- var zBaseProofJwtHeader = z6.object({
618
- alg: z6.string().min(1),
761
+ import { z as z8 } from "zod";
762
+ var zBaseProofJwtHeader = z8.object({
763
+ alg: z8.string().min(1),
619
764
  jwk: zJwk,
620
- typ: z6.literal("openid4vci-proof+jwt")
765
+ typ: z8.literal("openid4vci-proof+jwt")
621
766
  });
622
767
  var zProofJwtHeaderV1_0 = zBaseProofJwtHeader.loose();
623
768
  var zProofJwtHeaderV1_3 = zBaseProofJwtHeader.extend({
624
- key_attestation: z6.string().min(1)
769
+ key_attestation: z8.string().min(1)
625
770
  }).loose();
626
- var zProofJwtPayload = z6.looseObject({
627
- aud: z6.string().min(1),
628
- iat: z6.number(),
629
- iss: z6.string().min(1).optional(),
630
- nonce: z6.string().min(1)
771
+ var zProofJwtPayload = z8.looseObject({
772
+ aud: z8.string().min(1),
773
+ iat: z8.number(),
774
+ iss: z8.string().min(1).optional(),
775
+ nonce: z8.string().min(1)
631
776
  });
632
777
 
633
778
  // src/credential-request/parse-credential-request.ts
@@ -692,7 +837,7 @@ function parseProofJwt(options) {
692
837
  errorMessagePrefix: "Error decoding credential request proof JWT:",
693
838
  jwt: options.jwt
694
839
  });
695
- const headerValidation = options.itWalletSpecsVersion === ItWalletSpecsVersion4.V1_3 || options.itWalletSpecsVersion === ItWalletSpecsVersion4.V1_4 ? zProofJwtHeaderV1_3.safeParse(decoded.header) : zProofJwtHeaderV1_0.safeParse(decoded.header);
840
+ const headerValidation = options.itWalletSpecsVersion === ItWalletSpecsVersion7.V1_3 || options.itWalletSpecsVersion === ItWalletSpecsVersion7.V1_4 ? zProofJwtHeaderV1_3.safeParse(decoded.header) : zProofJwtHeaderV1_0.safeParse(decoded.header);
696
841
  if (!headerValidation.success) {
697
842
  throw new ValidationError4(
698
843
  "Credential proof JWT header is invalid or missing required claims"
@@ -717,7 +862,27 @@ function parseProofJwt(options) {
717
862
  proofType: "jwt"
718
863
  };
719
864
  }
720
- function normalizeProofs(options) {
865
+ async function validateProofJwkUniqueness(options) {
866
+ if (options.proofs.length <= 1) {
867
+ return;
868
+ }
869
+ const thumbprints = await Promise.all(
870
+ options.proofs.map(
871
+ (proof) => calculateJwkThumbprint2({
872
+ hashAlgorithm: HashAlgorithm2.Sha256,
873
+ hashCallback: options.callbacks.hash,
874
+ jwk: proof.header.jwk
875
+ })
876
+ )
877
+ );
878
+ const uniqueThumbprints = new Set(thumbprints);
879
+ if (uniqueThumbprints.size !== thumbprints.length) {
880
+ throw new ValidationError4(
881
+ "Credential request proofs must use unique jwk header values"
882
+ );
883
+ }
884
+ }
885
+ async function normalizeProofs(options) {
721
886
  if ("proof" in options.credentialRequest) {
722
887
  return [
723
888
  parseProofJwt({
@@ -728,7 +893,7 @@ function normalizeProofs(options) {
728
893
  })
729
894
  ];
730
895
  }
731
- return options.credentialRequest.proofs.jwt.map(
896
+ const proofs = options.credentialRequest.proofs.jwt.map(
732
897
  (jwt) => parseProofJwt({
733
898
  expected: options.expected,
734
899
  grantType: options.grantType,
@@ -736,14 +901,20 @@ function normalizeProofs(options) {
736
901
  jwt
737
902
  })
738
903
  );
904
+ await validateProofJwkUniqueness({
905
+ callbacks: options.callbacks,
906
+ proofs
907
+ });
908
+ return proofs;
739
909
  }
740
- function toResult(options) {
910
+ async function toResult(options) {
741
911
  validateExpectedValues(options.credentialRequest, options.expected);
742
912
  validateTransactionContext({
743
913
  credentialRequest: options.credentialRequest,
744
914
  isDeferredFlow: options.isDeferredFlow
745
915
  });
746
- const proofs = normalizeProofs({
916
+ const proofs = await normalizeProofs({
917
+ callbacks: options.callbacks,
747
918
  credentialRequest: options.credentialRequest,
748
919
  expected: options.expected,
749
920
  grantType: options.grantType,
@@ -802,12 +973,13 @@ function parseCredentialRequestV1_0(options) {
802
973
  );
803
974
  return toResult({
804
975
  accessToken: options.accessToken,
976
+ callbacks: options.callbacks,
805
977
  credentialRequest,
806
978
  dpopProof: options.dpopProof,
807
979
  expected: options.expected,
808
980
  grantType: options.grantType,
809
981
  isDeferredFlow: options.isDeferredFlow,
810
- itWalletSpecsVersion: ItWalletSpecsVersion4.V1_0
982
+ itWalletSpecsVersion: ItWalletSpecsVersion7.V1_0
811
983
  });
812
984
  }
813
985
  function parseCredentialRequestV1_3(options) {
@@ -818,12 +990,13 @@ function parseCredentialRequestV1_3(options) {
818
990
  );
819
991
  return toResult({
820
992
  accessToken: options.accessToken,
993
+ callbacks: options.callbacks,
821
994
  credentialRequest,
822
995
  dpopProof: options.dpopProof,
823
996
  expected: options.expected,
824
997
  grantType: options.grantType,
825
998
  isDeferredFlow: options.isDeferredFlow,
826
- itWalletSpecsVersion: ItWalletSpecsVersion4.V1_3
999
+ itWalletSpecsVersion: ItWalletSpecsVersion7.V1_3
827
1000
  });
828
1001
  }
829
1002
  function parseCredentialRequestV1_4(options) {
@@ -834,27 +1007,28 @@ function parseCredentialRequestV1_4(options) {
834
1007
  );
835
1008
  return toResult({
836
1009
  accessToken: options.accessToken,
1010
+ callbacks: options.callbacks,
837
1011
  credentialRequest,
838
1012
  dpopProof: options.dpopProof,
839
1013
  expected: options.expected,
840
1014
  grantType: options.grantType,
841
1015
  isDeferredFlow: options.isDeferredFlow,
842
- itWalletSpecsVersion: ItWalletSpecsVersion4.V1_4
1016
+ itWalletSpecsVersion: ItWalletSpecsVersion7.V1_4
843
1017
  // V1_4 reuses V1_3 proof schema
844
1018
  });
845
1019
  }
846
- var dispatchParseCredentialRequest = createVersionDispatcher2({
847
- [ItWalletSpecsVersion4.V1_0]: parseCredentialRequestV1_0,
848
- [ItWalletSpecsVersion4.V1_3]: parseCredentialRequestV1_3,
849
- [ItWalletSpecsVersion4.V1_4]: parseCredentialRequestV1_4
1020
+ var dispatchParseCredentialRequest = createVersionDispatcher4({
1021
+ [ItWalletSpecsVersion7.V1_0]: parseCredentialRequestV1_0,
1022
+ [ItWalletSpecsVersion7.V1_3]: parseCredentialRequestV1_3,
1023
+ [ItWalletSpecsVersion7.V1_4]: parseCredentialRequestV1_4
850
1024
  });
851
- function parseCredentialRequest(options) {
1025
+ async function parseCredentialRequest(options) {
852
1026
  const grantType = options.grantType ?? "authorization_code";
853
1027
  const isDeferredFlow = options.isDeferredFlow ?? false;
854
1028
  try {
855
1029
  const accessToken = parseAuthorizationHeader(options.headers);
856
1030
  const dpopProof = parseDpopProof(options.headers);
857
- return dispatchParseCredentialRequest({
1031
+ return await dispatchParseCredentialRequest({
858
1032
  ...options,
859
1033
  accessToken,
860
1034
  dpopProof,
@@ -862,7 +1036,7 @@ function parseCredentialRequest(options) {
862
1036
  isDeferredFlow
863
1037
  });
864
1038
  } catch (error) {
865
- if (error instanceof ItWalletSpecsVersionError || error instanceof Oauth2JwtParseError || error instanceof ValidationError4 || error instanceof CredentialAuthorizationHeaderError || error instanceof MissingDpopProofError) {
1039
+ if (error instanceof ItWalletSpecsVersionError4 || error instanceof Oauth2JwtParseError || error instanceof ValidationError4 || error instanceof CredentialAuthorizationHeaderError || error instanceof MissingDpopProofError) {
866
1040
  throw error;
867
1041
  }
868
1042
  throw new ParseCredentialRequestError(
@@ -873,18 +1047,18 @@ function parseCredentialRequest(options) {
873
1047
  }
874
1048
 
875
1049
  // src/credential-request/verify-credential-request-jwt-proof.ts
876
- import { calculateJwkThumbprint as calculateJwkThumbprint2, jwtSignerFromJwt as jwtSignerFromJwt3 } from "@openid4vc/oauth2";
1050
+ import { calculateJwkThumbprint as calculateJwkThumbprint3, jwtSignerFromJwt as jwtSignerFromJwt3 } from "@openid4vc/oauth2";
877
1051
  import {
878
- HashAlgorithm as HashAlgorithm2,
1052
+ HashAlgorithm as HashAlgorithm3,
879
1053
  Oauth2JwtParseError as Oauth2JwtParseError3,
880
1054
  decodeJwt as decodeJwt3,
881
1055
  verifyJwt as verifyJwt3
882
1056
  } from "@pagopa/io-wallet-oauth2";
883
1057
  import {
884
- ItWalletSpecsVersion as ItWalletSpecsVersion5,
885
- ItWalletSpecsVersionError as ItWalletSpecsVersionError2,
1058
+ ItWalletSpecsVersion as ItWalletSpecsVersion8,
1059
+ ItWalletSpecsVersionError as ItWalletSpecsVersionError5,
886
1060
  ValidationError as ValidationError6,
887
- createVersionDispatcher as createVersionDispatcher3,
1061
+ createVersionDispatcher as createVersionDispatcher5,
888
1062
  verifyJwtIatOrThrow
889
1063
  } from "@pagopa/io-wallet-utils";
890
1064
 
@@ -901,33 +1075,33 @@ import { ValidationError as ValidationError5 } from "@pagopa/io-wallet-utils";
901
1075
  import { zCertificateChain, zJwk as zJwk2, zTrustChain } from "@pagopa/io-wallet-oauth2";
902
1076
  import { zKeyStorageLevelV1_3 } from "@pagopa/io-wallet-oid-federation";
903
1077
  import { zItwSupportedSignatureAlg } from "@pagopa/io-wallet-utils";
904
- import { z as z7 } from "zod";
905
- var zStatusList = z7.object({
906
- idx: z7.number(),
907
- uri: z7.url()
1078
+ import { z as z9 } from "zod";
1079
+ var zStatusList = z9.object({
1080
+ idx: z9.number(),
1081
+ uri: z9.url()
908
1082
  });
909
- var zKeyAttestationStatus = z7.object({
1083
+ var zKeyAttestationStatus = z9.object({
910
1084
  status_list: zStatusList
911
1085
  });
912
1086
  var zKeyAttestationAlg = zItwSupportedSignatureAlg;
913
- var zKeyAttestationHeader = z7.object({
1087
+ var zKeyAttestationHeader = z9.object({
914
1088
  alg: zKeyAttestationAlg,
915
- kid: z7.string(),
1089
+ kid: z9.string(),
916
1090
  trust_chain: zTrustChain.optional(),
917
- typ: z7.literal("key-attestation+jwt"),
1091
+ typ: z9.literal("key-attestation+jwt"),
918
1092
  x5c: zCertificateChain
919
1093
  });
920
- var zKeyAttestationPayload = z7.object({
921
- attested_keys: z7.array(zJwk2).nonempty(),
922
- certification: z7.string().optional(),
923
- exp: z7.number(),
924
- iat: z7.number(),
925
- iss: z7.string(),
926
- key_storage: z7.array(zKeyStorageLevelV1_3).nonempty(),
1094
+ var zKeyAttestationPayload = z9.object({
1095
+ attested_keys: z9.array(zJwk2).nonempty(),
1096
+ certification: z9.string().optional(),
1097
+ exp: z9.number(),
1098
+ iat: z9.number(),
1099
+ iss: z9.string(),
1100
+ key_storage: z9.array(zKeyStorageLevelV1_3).nonempty(),
927
1101
  status: zKeyAttestationStatus,
928
- user_authentication: z7.array(zKeyStorageLevelV1_3).nonempty()
1102
+ user_authentication: z9.array(zKeyStorageLevelV1_3).nonempty()
929
1103
  });
930
- var zKeyAttestationTypeHeader = z7.literal("key-attestation+jwt");
1104
+ var zKeyAttestationTypeHeader = z9.literal("key-attestation+jwt");
931
1105
  var keyAttestationTypeHeader = zKeyAttestationTypeHeader.value;
932
1106
 
933
1107
  // src/credential-request/verify-key-attestation-jwt.ts
@@ -974,15 +1148,15 @@ async function verifyKeyAttestationJwt(options) {
974
1148
 
975
1149
  // src/credential-request/verify-credential-request-jwt-proof.ts
976
1150
  async function isJwkInSet(options) {
977
- const targetThumbprint = await calculateJwkThumbprint2({
978
- hashAlgorithm: HashAlgorithm2.Sha256,
1151
+ const targetThumbprint = await calculateJwkThumbprint3({
1152
+ hashAlgorithm: HashAlgorithm3.Sha256,
979
1153
  hashCallback: options.callbacks.hash,
980
1154
  jwk: options.jwk
981
1155
  });
982
1156
  const thumbprints = await Promise.all(
983
1157
  options.jwks.map(
984
- (jwk) => calculateJwkThumbprint2({
985
- hashAlgorithm: HashAlgorithm2.Sha256,
1158
+ (jwk) => calculateJwkThumbprint3({
1159
+ hashAlgorithm: HashAlgorithm3.Sha256,
986
1160
  hashCallback: options.callbacks.hash,
987
1161
  jwk
988
1162
  })
@@ -1077,10 +1251,10 @@ async function verifyProofV1_3(options) {
1077
1251
  }
1078
1252
  return { header, keyAttestation: keyAttestationResult, payload, signer };
1079
1253
  }
1080
- var dispatchVerifyProof = createVersionDispatcher3({
1081
- [ItWalletSpecsVersion5.V1_0]: (o) => verifyProofV1_0(o),
1082
- [ItWalletSpecsVersion5.V1_3]: (o) => verifyProofV1_3(o),
1083
- [ItWalletSpecsVersion5.V1_4]: (o) => verifyProofV1_3(o)
1254
+ var dispatchVerifyProof = createVersionDispatcher5({
1255
+ [ItWalletSpecsVersion8.V1_0]: (o) => verifyProofV1_0(o),
1256
+ [ItWalletSpecsVersion8.V1_3]: (o) => verifyProofV1_3(o),
1257
+ [ItWalletSpecsVersion8.V1_4]: (o) => verifyProofV1_3(o)
1084
1258
  });
1085
1259
  async function verifyCredentialRequestJwtProof(options) {
1086
1260
  try {
@@ -1092,7 +1266,7 @@ async function verifyCredentialRequestJwtProof(options) {
1092
1266
  }
1093
1267
  return await dispatchVerifyProof({ ...options, now });
1094
1268
  } catch (error) {
1095
- if (error instanceof VerifyCredentialRequestJwtProofError || error instanceof VerifyKeyAttestationJwtError || error instanceof ItWalletSpecsVersionError2 || error instanceof ValidationError6 || error instanceof Oauth2JwtParseError3) {
1269
+ if (error instanceof VerifyCredentialRequestJwtProofError || error instanceof VerifyKeyAttestationJwtError || error instanceof ItWalletSpecsVersionError5 || error instanceof ValidationError6 || error instanceof Oauth2JwtParseError3) {
1096
1270
  throw error;
1097
1271
  }
1098
1272
  throw new VerifyCredentialRequestJwtProofError(
@@ -1104,39 +1278,39 @@ async function verifyCredentialRequestJwtProof(options) {
1104
1278
 
1105
1279
  // src/credential-response/create-credential-response.ts
1106
1280
  import {
1107
- ItWalletSpecsVersion as ItWalletSpecsVersion6,
1281
+ ItWalletSpecsVersion as ItWalletSpecsVersion9,
1108
1282
  ValidationError as ValidationError7,
1109
- createVersionDispatcher as createVersionDispatcher4
1283
+ createVersionDispatcher as createVersionDispatcher6
1110
1284
  } from "@pagopa/io-wallet-utils";
1111
1285
 
1112
1286
  // src/credential-response/v1.0/create-credential-response.ts
1113
1287
  import { parseWithErrorHandling as parseWithErrorHandling4 } from "@pagopa/io-wallet-utils";
1114
1288
 
1115
1289
  // src/credential-response/v1.0/z-credential-response.ts
1116
- import { z as z9 } from "zod";
1290
+ import { z as z11 } from "zod";
1117
1291
 
1118
1292
  // src/credential-response/z-immediate-credential-response.ts
1119
- import { z as z8 } from "zod";
1120
- var zCredentialObject = z8.object({
1121
- credential: z8.string()
1293
+ import { z as z10 } from "zod";
1294
+ var zCredentialObject = z10.object({
1295
+ credential: z10.string()
1122
1296
  });
1123
- var zImmediateCredentialResponse = z8.strictObject({
1124
- credentials: z8.array(zCredentialObject).nonempty().describe(
1297
+ var zImmediateCredentialResponse = z10.strictObject({
1298
+ credentials: z10.array(zCredentialObject).nonempty().describe(
1125
1299
  "Conditional. Array of issued Digital Credentials as JSON objects with `credential` member containing encoded credential string. Present for immediate issuance (HTTP 200)."
1126
1300
  ),
1127
- notification_id: z8.string().optional().describe(
1301
+ notification_id: z10.string().optional().describe(
1128
1302
  "OPTIONAL. Identifier for notification requests. Only present with credentials parameter."
1129
1303
  )
1130
1304
  });
1131
1305
 
1132
1306
  // src/credential-response/v1.0/z-credential-response.ts
1133
- var zDeferredCredentialResponseV1_0 = z9.strictObject({
1134
- lead_time: z9.number().int().positive().describe(
1307
+ var zDeferredCredentialResponseV1_0 = z11.strictObject({
1308
+ lead_time: z11.number().int().positive().describe(
1135
1309
  "REQUIRED if credentials is not present, otherwise it MUST NOT be present. The amount of time (in seconds) required before making a Deferred Credential Request."
1136
1310
  ),
1137
- transaction_id: z9.string().nonempty()
1311
+ transaction_id: z11.string().nonempty()
1138
1312
  });
1139
- var zCredentialResponseV1_0 = z9.union([
1313
+ var zCredentialResponseV1_0 = z11.union([
1140
1314
  zImmediateCredentialResponse,
1141
1315
  zDeferredCredentialResponseV1_0
1142
1316
  ]);
@@ -1169,14 +1343,14 @@ function createCredentialResponseV1_0(flow) {
1169
1343
  import { parseWithErrorHandling as parseWithErrorHandling5 } from "@pagopa/io-wallet-utils";
1170
1344
 
1171
1345
  // src/credential-response/v1.3/z-credential-response.ts
1172
- import { z as z10 } from "zod";
1173
- var zDeferredCredentialResponseV1_3 = z10.strictObject({
1174
- interval: z10.number().int().positive().describe(
1346
+ import { z as z12 } from "zod";
1347
+ var zDeferredCredentialResponseV1_3 = z12.strictObject({
1348
+ interval: z12.number().int().positive().describe(
1175
1349
  "REQUIRED if transaction_id is present, otherwise it MUST NOT be present. The amount of time (in seconds) required before making a Deferred Credential Request"
1176
1350
  ),
1177
- transaction_id: z10.string().nonempty()
1351
+ transaction_id: z12.string().nonempty()
1178
1352
  });
1179
- var zCredentialResponseV1_3 = z10.union([
1353
+ var zCredentialResponseV1_3 = z12.union([
1180
1354
  zImmediateCredentialResponse,
1181
1355
  zDeferredCredentialResponseV1_3
1182
1356
  ]);
@@ -1206,14 +1380,14 @@ function createCredentialResponseV1_3(flow) {
1206
1380
  }
1207
1381
 
1208
1382
  // src/credential-response/create-credential-response.ts
1209
- var dispatchBuildVersionedResponse = createVersionDispatcher4({
1210
- [ItWalletSpecsVersion6.V1_0]: (o) => createCredentialResponseV1_0(
1383
+ var dispatchBuildVersionedResponse = createVersionDispatcher6({
1384
+ [ItWalletSpecsVersion9.V1_0]: (o) => createCredentialResponseV1_0(
1211
1385
  o.flow
1212
1386
  ),
1213
- [ItWalletSpecsVersion6.V1_3]: (o) => createCredentialResponseV1_3(
1387
+ [ItWalletSpecsVersion9.V1_3]: (o) => createCredentialResponseV1_3(
1214
1388
  o.flow
1215
1389
  ),
1216
- [ItWalletSpecsVersion6.V1_4]: (o) => createCredentialResponseV1_3(
1390
+ [ItWalletSpecsVersion9.V1_4]: (o) => createCredentialResponseV1_3(
1217
1391
  o.flow
1218
1392
  // V1_4 reuses V1_3 credential response schema — no breaking changes between versions.
1219
1393
  // Verified against compare/1.3.3...1.4.1: credential response parameters identical.
@@ -1274,10 +1448,10 @@ import {
1274
1448
 
1275
1449
  // src/credential-response/z-credential-response.ts
1276
1450
  import { zAlgValueNotNone, zJwk as zJwk3 } from "@pagopa/io-wallet-oauth2";
1277
- import { z as z11 } from "zod";
1278
- var zCredentialResponseEncryption = z11.looseObject({
1451
+ import { z as z13 } from "zod";
1452
+ var zCredentialResponseEncryption = z13.looseObject({
1279
1453
  alg: zAlgValueNotNone,
1280
- enc: z11.string(),
1454
+ enc: z13.string(),
1281
1455
  jwk: zJwk3
1282
1456
  });
1283
1457
 
@@ -1325,16 +1499,16 @@ async function fetchCredentialResponse(options) {
1325
1499
  import { decodeJwt as decodeJwt4 } from "@pagopa/io-wallet-oauth2";
1326
1500
  import { itWalletEntityStatementClaimsSchema as itWalletEntityStatementClaimsSchema2 } from "@pagopa/io-wallet-oid-federation";
1327
1501
  import {
1328
- ItWalletSpecsVersion as ItWalletSpecsVersion7,
1329
- ItWalletSpecsVersionError as ItWalletSpecsVersionError3,
1502
+ ItWalletSpecsVersion as ItWalletSpecsVersion10,
1503
+ ItWalletSpecsVersionError as ItWalletSpecsVersionError6,
1330
1504
  UnexpectedStatusCodeError as UnexpectedStatusCodeError4,
1331
1505
  ValidationError as ValidationError9,
1332
1506
  createFetcher as createFetcher4,
1333
- createVersionDispatcher as createVersionDispatcher5,
1507
+ createVersionDispatcher as createVersionDispatcher7,
1334
1508
  hasStatusOrThrow as hasStatusOrThrow4,
1335
1509
  parseWithErrorHandling as parseWithErrorHandling7
1336
1510
  } from "@pagopa/io-wallet-utils";
1337
- import z13 from "zod";
1511
+ import z15 from "zod";
1338
1512
 
1339
1513
  // src/metadata/z-metadata-response.ts
1340
1514
  import {
@@ -1342,23 +1516,29 @@ import {
1342
1516
  itWalletMetadataV1_0,
1343
1517
  itWalletMetadataV1_3
1344
1518
  } from "@pagopa/io-wallet-oid-federation";
1345
- import { z as z12 } from "zod";
1346
- var zMetadataResponseV1_0 = z12.object({
1347
- discoveredVia: z12.enum(["federation"]),
1519
+ import { z as z14 } from "zod";
1520
+ var zMetadataResponseV1_0 = z14.object({
1521
+ discoveredVia: z14.enum(["federation"]),
1348
1522
  metadata: itWalletMetadataV1_0,
1349
1523
  openid_federation_claims: itWalletEntityStatementClaimsSchema
1350
1524
  });
1351
- var zMetadataResponseV1_3 = z12.object({
1352
- discoveredVia: z12.enum(["federation", "oid4vci"]),
1525
+ var zMetadataResponseV1_3 = z14.object({
1526
+ /**
1527
+ * Entity statement claims of the Authorization Server, present only when the
1528
+ * selected authorization server was resolved through a federation entity
1529
+ * distinct from the Credential Issuer.
1530
+ */
1531
+ authorization_server_federation_claims: itWalletEntityStatementClaimsSchema.optional(),
1532
+ discoveredVia: z14.enum(["federation", "oid4vci"]),
1353
1533
  metadata: itWalletMetadataV1_3,
1354
1534
  openid_federation_claims: itWalletEntityStatementClaimsSchema.optional()
1355
1535
  });
1356
- var zMetadataResponse = z12.union([
1536
+ var zMetadataResponse = z14.union([
1357
1537
  zMetadataResponseV1_0,
1358
1538
  zMetadataResponseV1_3
1359
1539
  ]);
1360
- var zPartialIssuerMetadata = z12.looseObject({
1361
- authorization_servers: z12.array(z12.string()).optional()
1540
+ var zPartialIssuerMetadata = z14.looseObject({
1541
+ authorization_servers: z14.tuple([z14.url()], z14.url()).optional()
1362
1542
  });
1363
1543
 
1364
1544
  // src/metadata/fetch-metadata.ts
@@ -1410,7 +1590,48 @@ async function tryFederationDiscovery(fetch, baseUrl, verifyJwt4) {
1410
1590
  return void 0;
1411
1591
  }
1412
1592
  }
1413
- async function fallbackDiscovery(fetch, baseUrl) {
1593
+ async function applyFederationAuthorizationServerSelection(fetch, federationResult, authorizationServer, verifyJwt4) {
1594
+ const credentialIssuer = federationResult.metadata?.openid_credential_issuer?.credential_issuer;
1595
+ const authorizationServers = federationResult.metadata?.openid_credential_issuer?.authorization_servers;
1596
+ let selectedAuthorizationServer;
1597
+ if (authorizationServer) {
1598
+ assertAuthorizationServerAllowed(authorizationServer, authorizationServers);
1599
+ selectedAuthorizationServer = authorizationServer;
1600
+ } else if (authorizationServers && authorizationServers.length > 0) {
1601
+ selectedAuthorizationServer = credentialIssuer && authorizationServers.includes(credentialIssuer) ? credentialIssuer : authorizationServers[0];
1602
+ } else {
1603
+ selectedAuthorizationServer = credentialIssuer;
1604
+ }
1605
+ if (!selectedAuthorizationServer || selectedAuthorizationServer === credentialIssuer) {
1606
+ return federationResult;
1607
+ }
1608
+ const parsedSelectedAuthorizationServer = z15.url().safeParse(selectedAuthorizationServer);
1609
+ if (!parsedSelectedAuthorizationServer.success || !parsedSelectedAuthorizationServer.data.startsWith("https://")) {
1610
+ throw new ValidationError9(
1611
+ "selected authorization server is not a valid HTTPS URL"
1612
+ );
1613
+ }
1614
+ const authorizationServerResult = await tryFederationDiscovery(
1615
+ fetch,
1616
+ parsedSelectedAuthorizationServer.data,
1617
+ verifyJwt4
1618
+ );
1619
+ const resolvedAuthorizationServer = authorizationServerResult?.metadata?.oauth_authorization_server;
1620
+ if (!resolvedAuthorizationServer) {
1621
+ throw new ValidationError9(
1622
+ `Federation discovery did not yield oauth_authorization_server metadata for authorization server '${selectedAuthorizationServer}'`
1623
+ );
1624
+ }
1625
+ return {
1626
+ ...federationResult,
1627
+ authorization_server_federation_claims: authorizationServerResult.openid_federation_claims,
1628
+ metadata: {
1629
+ ...federationResult.metadata,
1630
+ oauth_authorization_server: resolvedAuthorizationServer
1631
+ }
1632
+ };
1633
+ }
1634
+ async function fallbackDiscovery(fetch, baseUrl, authorizationServer) {
1414
1635
  const issuerUrl = new URL(
1415
1636
  ".well-known/openid-credential-issuer",
1416
1637
  ensureTrailingSlash(baseUrl)
@@ -1423,12 +1644,14 @@ async function fallbackDiscovery(fetch, baseUrl) {
1423
1644
  "Failed to parse credential issuer metadata"
1424
1645
  );
1425
1646
  const authorizationServers = issuerJson.authorization_servers;
1647
+ assertAuthorizationServerAllowed(authorizationServer, authorizationServers);
1426
1648
  let oauthAuthorizationServer;
1427
1649
  if (authorizationServers && authorizationServers.length > 0) {
1428
- const parsedUrl = z13.url().safeParse(authorizationServers[0]);
1650
+ const selectedAuthorizationServer = authorizationServer ?? authorizationServers[0];
1651
+ const parsedUrl = z15.url().safeParse(selectedAuthorizationServer);
1429
1652
  if (!parsedUrl.success || !parsedUrl.data.startsWith("https://")) {
1430
1653
  throw new ValidationError9(
1431
- "authorization_servers[0] is not a valid HTTPS URL"
1654
+ "selected authorization server is not a valid HTTPS URL"
1432
1655
  );
1433
1656
  }
1434
1657
  const authServerUrl = new URL(
@@ -1474,22 +1697,31 @@ async function fetchMetadataV1_3(options) {
1474
1697
  options.credentialIssuerUrl,
1475
1698
  options.callbacks.verifyJwt
1476
1699
  );
1477
- const raw = federationResult ?? await fallbackDiscovery(fetch, options.credentialIssuerUrl);
1700
+ const raw = federationResult ? await applyFederationAuthorizationServerSelection(
1701
+ fetch,
1702
+ federationResult,
1703
+ options.authorizationServer,
1704
+ options.callbacks.verifyJwt
1705
+ ) : await fallbackDiscovery(
1706
+ fetch,
1707
+ options.credentialIssuerUrl,
1708
+ options.authorizationServer
1709
+ );
1478
1710
  return parseWithErrorHandling7(
1479
1711
  zMetadataResponseV1_3,
1480
1712
  raw,
1481
1713
  "Failed to parse v1.3 metadata response"
1482
1714
  );
1483
1715
  }
1484
- var dispatchFetchMetadata = createVersionDispatcher5({
1485
- [ItWalletSpecsVersion7.V1_0]: (o) => fetchMetadataV1_0(o),
1486
- [ItWalletSpecsVersion7.V1_3]: (o) => fetchMetadataV1_3(o),
1716
+ var dispatchFetchMetadata = createVersionDispatcher7({
1717
+ [ItWalletSpecsVersion10.V1_0]: (o) => fetchMetadataV1_0(o),
1718
+ [ItWalletSpecsVersion10.V1_3]: (o) => fetchMetadataV1_3(o),
1487
1719
  // V1_4 reuses V1_3 metadata schema — no breaking changes between versions.
1488
- [ItWalletSpecsVersion7.V1_4]: (o) => fetchMetadataV1_3(o)
1720
+ [ItWalletSpecsVersion10.V1_4]: (o) => fetchMetadataV1_3(o)
1489
1721
  });
1490
1722
  async function fetchMetadata(options) {
1491
1723
  try {
1492
- const urlValidation = z13.url().safeParse(options.credentialIssuerUrl);
1724
+ const urlValidation = z15.url().safeParse(options.credentialIssuerUrl);
1493
1725
  if (!urlValidation.success || !urlValidation.data.startsWith("https://")) {
1494
1726
  throw new ValidationError9(
1495
1727
  "credentialIssuerUrl must be a valid HTTPS URL"
@@ -1497,7 +1729,7 @@ async function fetchMetadata(options) {
1497
1729
  }
1498
1730
  return await dispatchFetchMetadata(options);
1499
1731
  } catch (error) {
1500
- if (error instanceof UnexpectedStatusCodeError4 || error instanceof ValidationError9 || error instanceof ItWalletSpecsVersionError3 || error instanceof FetchMetadataError) {
1732
+ if (error instanceof UnexpectedStatusCodeError4 || error instanceof ValidationError9 || error instanceof ItWalletSpecsVersionError6 || error instanceof CredentialOfferError || error instanceof FetchMetadataError) {
1501
1733
  throw error;
1502
1734
  }
1503
1735
  throw new FetchMetadataError("Unexpected error during metadata fetch", {
@@ -1513,7 +1745,7 @@ import {
1513
1745
  createWalletAttestationJwtV1_4
1514
1746
  } from "@pagopa/io-wallet-oauth2";
1515
1747
  import {
1516
- ItWalletSpecsVersion as ItWalletSpecsVersion8,
1748
+ ItWalletSpecsVersion as ItWalletSpecsVersion11,
1517
1749
  addSecondsToDate,
1518
1750
  dateToSeconds as dateToSeconds3,
1519
1751
  dispatchByVersion
@@ -1682,7 +1914,7 @@ var WalletProvider = class {
1682
1914
  */
1683
1915
  async createItWalletAttestationJwt(options) {
1684
1916
  return dispatchByVersion(this.specVersion, {
1685
- [ItWalletSpecsVersion8.V1_0]: () => {
1917
+ [ItWalletSpecsVersion11.V1_0]: () => {
1686
1918
  assertV1_0Options(options);
1687
1919
  return createWalletAttestationJwtV1_0({
1688
1920
  authenticatorAssuranceLevel: options.authenticatorAssuranceLevel,
@@ -1695,7 +1927,7 @@ var WalletProvider = class {
1695
1927
  walletName: options.walletName
1696
1928
  });
1697
1929
  },
1698
- [ItWalletSpecsVersion8.V1_3]: () => {
1930
+ [ItWalletSpecsVersion11.V1_3]: () => {
1699
1931
  assertV1_3Options(options);
1700
1932
  return createWalletAttestationJwtV1_3({
1701
1933
  callbacks: options.callbacks,
@@ -1709,7 +1941,7 @@ var WalletProvider = class {
1709
1941
  walletName: options.walletName
1710
1942
  });
1711
1943
  },
1712
- [ItWalletSpecsVersion8.V1_4]: () => {
1944
+ [ItWalletSpecsVersion11.V1_4]: () => {
1713
1945
  assertV1_4Options(options);
1714
1946
  return createWalletAttestationJwtV1_4({
1715
1947
  callbacks: options.callbacks,
@@ -1756,8 +1988,14 @@ export {
1756
1988
  verifyAuthorizationResponseFormPostJWT,
1757
1989
  verifyCredentialRequestJwtProof,
1758
1990
  verifyKeyAttestationJwt,
1991
+ zAuthorizationCodeGrantV1_3,
1992
+ zAuthorizationCodeGrantV1_4,
1759
1993
  zAuthorizationResponse,
1760
1994
  zCredentialObject,
1995
+ zCredentialOfferGrantsV1_3,
1996
+ zCredentialOfferGrantsV1_4,
1997
+ zCredentialOfferV1_3,
1998
+ zCredentialOfferV1_4,
1761
1999
  zCredentialRequestV1_0,
1762
2000
  zCredentialRequestV1_3,
1763
2001
  zCredentialResponseEncryption,