@pagopa/io-wallet-oid4vp 1.2.0 → 1.3.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.d.mts +85 -77
- package/dist/index.d.ts +85 -77
- package/dist/index.js +156 -146
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +163 -153
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -15,36 +15,40 @@ import {
|
|
|
15
15
|
|
|
16
16
|
// src/errors.ts
|
|
17
17
|
var Oid4vpError = class extends Error {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
18
|
+
statusCode;
|
|
19
|
+
constructor(message, options) {
|
|
20
|
+
super(message, options);
|
|
21
21
|
this.name = "Oid4vpError";
|
|
22
|
+
this.statusCode = options?.statusCode;
|
|
22
23
|
}
|
|
23
24
|
};
|
|
24
25
|
var ParseAuthorizeRequestError = class extends Oid4vpError {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
26
|
+
statusCode;
|
|
27
|
+
constructor(message, options) {
|
|
28
|
+
super(message, options);
|
|
28
29
|
this.name = "ParseAuthorizeRequestError";
|
|
30
|
+
this.statusCode = options?.statusCode;
|
|
29
31
|
}
|
|
30
32
|
};
|
|
31
33
|
var FetchAuthorizationResponseError = class extends Oid4vpError {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
34
|
+
statusCode;
|
|
35
|
+
constructor(message, options) {
|
|
36
|
+
super(message, options);
|
|
35
37
|
this.name = "FetchAuthorizationResponseError";
|
|
38
|
+
this.statusCode = options?.statusCode;
|
|
36
39
|
}
|
|
37
40
|
};
|
|
38
41
|
var CreateAuthorizationResponseError = class extends Oid4vpError {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
+
statusCode;
|
|
43
|
+
constructor(message, options) {
|
|
44
|
+
super(message, options);
|
|
42
45
|
this.name = "CreateAuthorizationResponseError";
|
|
46
|
+
this.statusCode = options?.statusCode;
|
|
43
47
|
}
|
|
44
48
|
};
|
|
45
49
|
var InvalidRequestUriMethodError = class extends Oid4vpError {
|
|
46
|
-
constructor(message) {
|
|
47
|
-
super(message);
|
|
50
|
+
constructor(message, options) {
|
|
51
|
+
super(message, options);
|
|
48
52
|
this.name = "InvalidRequestUriMethodError";
|
|
49
53
|
}
|
|
50
54
|
};
|
|
@@ -348,6 +352,7 @@ async function parseAuthorizeRequest(options) {
|
|
|
348
352
|
try {
|
|
349
353
|
const headerSchema = options.config.isVersion(ItWalletSpecsVersion2.V1_0) ? zOpenid4vpAuthorizationRequestHeaderV1_0 : zOpenid4vpAuthorizationRequestHeaderV1_3;
|
|
350
354
|
const decoded = decodeJwt({
|
|
355
|
+
errorMessagePrefix: "Error decoding authorization request JWT:",
|
|
351
356
|
headerSchema,
|
|
352
357
|
jwt: options.requestObjectJwt,
|
|
353
358
|
payloadSchema: zOpenid4vpAuthorizationRequestPayload
|
|
@@ -401,17 +406,91 @@ function extractEncryptionJwkFromJwks(jwks, {
|
|
|
401
406
|
return encFiltered.length > 0 ? encFiltered[0] : jwks.keys[0];
|
|
402
407
|
}
|
|
403
408
|
|
|
404
|
-
// src/
|
|
409
|
+
// src/authorization-response/create-authorization-response.ts
|
|
410
|
+
async function createAuthorizationResponse(options) {
|
|
411
|
+
try {
|
|
412
|
+
const encryptionAlg = options.authorization_encrypted_response_alg ?? "ECDH-ES";
|
|
413
|
+
const encryptionEnc = options.authorization_encrypted_response_enc ?? "A256GCM";
|
|
414
|
+
const { requestObject } = options;
|
|
415
|
+
const clientMetadata = requestObject.client_metadata;
|
|
416
|
+
const clientIdPrefix = extractClientIdPrefix(requestObject.client_id);
|
|
417
|
+
if (clientIdPrefix === "x509_hash" /* X509_HASH */ && !clientMetadata) {
|
|
418
|
+
throw new CreateAuthorizationResponseError(
|
|
419
|
+
"clientMetadata is required when client_id uses x509_hash prefix"
|
|
420
|
+
);
|
|
421
|
+
}
|
|
422
|
+
const effectiveClientMetadata = clientIdPrefix === "openid_federation" /* OPENID_FEDERATION */ ? void 0 : clientMetadata;
|
|
423
|
+
const authorizationResponsePayload = {
|
|
424
|
+
state: requestObject.state,
|
|
425
|
+
vp_token: options.vp_token
|
|
426
|
+
};
|
|
427
|
+
const encryptionJwks = effectiveClientMetadata ? effectiveClientMetadata.jwks : options.rpJwks.jwks;
|
|
428
|
+
const encryptionJwk = extractEncryptionJwkFromJwks(encryptionJwks, {
|
|
429
|
+
supportedAlgValues: [encryptionAlg]
|
|
430
|
+
});
|
|
431
|
+
if (!encryptionJwk) {
|
|
432
|
+
throw new CreateAuthorizationResponseError(
|
|
433
|
+
"No encryption JWK found in metadata"
|
|
434
|
+
);
|
|
435
|
+
}
|
|
436
|
+
const encValuesSupported = effectiveClientMetadata?.encrypted_response_enc_values_supported ?? options.rpJwks.encrypted_response_enc_values_supported;
|
|
437
|
+
let enc;
|
|
438
|
+
if (encValuesSupported) {
|
|
439
|
+
if (options.authorization_encrypted_response_enc !== void 0) {
|
|
440
|
+
enc = encValuesSupported.find(
|
|
441
|
+
(e) => e === options.authorization_encrypted_response_enc
|
|
442
|
+
) ?? encValuesSupported[0] ?? options.authorization_encrypted_response_enc;
|
|
443
|
+
} else {
|
|
444
|
+
enc = encValuesSupported[0] ?? encryptionEnc;
|
|
445
|
+
}
|
|
446
|
+
} else {
|
|
447
|
+
enc = encryptionEnc;
|
|
448
|
+
}
|
|
449
|
+
const alg = encryptionJwk.alg ?? encryptionAlg;
|
|
450
|
+
const nonceBytes = await options.callbacks.generateRandom(32);
|
|
451
|
+
const jweEncryptor = {
|
|
452
|
+
alg,
|
|
453
|
+
apu: encodeToBase64Url(nonceBytes),
|
|
454
|
+
apv: encodeToBase64Url(requestObject.nonce),
|
|
455
|
+
enc,
|
|
456
|
+
method: "jwk",
|
|
457
|
+
publicJwk: encryptionJwk
|
|
458
|
+
};
|
|
459
|
+
const plaintext = JSON.stringify(authorizationResponsePayload);
|
|
460
|
+
const { encryptionJwk: usedJwk, jwe } = await options.callbacks.encryptJwe(
|
|
461
|
+
jweEncryptor,
|
|
462
|
+
plaintext
|
|
463
|
+
);
|
|
464
|
+
return {
|
|
465
|
+
authorizationResponsePayload,
|
|
466
|
+
jarm: {
|
|
467
|
+
encryptionJwk: usedJwk,
|
|
468
|
+
responseJwe: jwe
|
|
469
|
+
}
|
|
470
|
+
};
|
|
471
|
+
} catch (error) {
|
|
472
|
+
if (error instanceof CreateAuthorizationResponseError) {
|
|
473
|
+
throw error;
|
|
474
|
+
}
|
|
475
|
+
throw new CreateAuthorizationResponseError(
|
|
476
|
+
`Unexpected error during authorization response creation: ${error instanceof Error ? error.message : String(error)}`
|
|
477
|
+
);
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
// src/authorization-response/fetch-authorization-response.ts
|
|
405
482
|
import {
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
483
|
+
CONTENT_TYPES,
|
|
484
|
+
HEADERS,
|
|
485
|
+
UnexpectedStatusCodeError as UnexpectedStatusCodeError2,
|
|
486
|
+
ValidationError as ValidationError4,
|
|
487
|
+
createFetcher as createFetcher2,
|
|
488
|
+
hasStatusOrThrow as hasStatusOrThrow2,
|
|
489
|
+
parseWithErrorHandling as parseWithErrorHandling2
|
|
490
|
+
} from "@pagopa/io-wallet-utils";
|
|
412
491
|
|
|
413
|
-
// src/
|
|
414
|
-
import
|
|
492
|
+
// src/authorization-response/z-authorization-response.ts
|
|
493
|
+
import z4 from "zod";
|
|
415
494
|
|
|
416
495
|
// src/vp-token/z-vp-token.ts
|
|
417
496
|
import { z as z3 } from "zod";
|
|
@@ -423,9 +502,66 @@ var zVpToken = z3.record(
|
|
|
423
502
|
}
|
|
424
503
|
);
|
|
425
504
|
|
|
505
|
+
// src/authorization-response/z-authorization-response.ts
|
|
506
|
+
var zOpenid4vpAuthorizationResponse = z4.object({
|
|
507
|
+
state: z4.string(),
|
|
508
|
+
vp_token: zVpToken
|
|
509
|
+
});
|
|
510
|
+
var zOpenid4vpAuthorizationResponseResult = z4.object({
|
|
511
|
+
redirect_uri: z4.url().optional()
|
|
512
|
+
});
|
|
513
|
+
|
|
514
|
+
// src/authorization-response/fetch-authorization-response.ts
|
|
515
|
+
async function fetchAuthorizationResponse(options) {
|
|
516
|
+
try {
|
|
517
|
+
const fetch = createFetcher2(options.callbacks.fetch);
|
|
518
|
+
const authorizationResponseResult = await fetch(
|
|
519
|
+
options.presentationResponseUri,
|
|
520
|
+
{
|
|
521
|
+
body: new URLSearchParams({
|
|
522
|
+
response: options.authorizationResponseJarm
|
|
523
|
+
}),
|
|
524
|
+
headers: {
|
|
525
|
+
[HEADERS.CONTENT_TYPE]: CONTENT_TYPES.FORM_URLENCODED
|
|
526
|
+
},
|
|
527
|
+
method: "POST"
|
|
528
|
+
}
|
|
529
|
+
);
|
|
530
|
+
await hasStatusOrThrow2(
|
|
531
|
+
200,
|
|
532
|
+
UnexpectedStatusCodeError2
|
|
533
|
+
)(authorizationResponseResult);
|
|
534
|
+
const authorizationResponseResultJson = await authorizationResponseResult.json();
|
|
535
|
+
return parseWithErrorHandling2(
|
|
536
|
+
zOpenid4vpAuthorizationResponseResult,
|
|
537
|
+
authorizationResponseResultJson
|
|
538
|
+
);
|
|
539
|
+
} catch (error) {
|
|
540
|
+
if (error instanceof UnexpectedStatusCodeError2 || error instanceof ValidationError4) {
|
|
541
|
+
throw error;
|
|
542
|
+
}
|
|
543
|
+
throw new FetchAuthorizationResponseError(
|
|
544
|
+
`Unexpected error sending authorization response: ${error instanceof Error ? error.message : String(error)}`
|
|
545
|
+
);
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
// src/authorization-response/parse-authorization-response.ts
|
|
550
|
+
import { parseWithErrorHandling as parseWithErrorHandling5 } from "@pagopa/io-wallet-utils";
|
|
551
|
+
|
|
552
|
+
// src/jarm/parse-jarm-authorization-response.ts
|
|
553
|
+
import {
|
|
554
|
+
decodeJwtHeader as decodeJwtHeader2,
|
|
555
|
+
zCompactJwe as zCompactJwe2,
|
|
556
|
+
zCompactJwt as zCompactJwt2
|
|
557
|
+
} from "@pagopa/io-wallet-oauth2";
|
|
558
|
+
import { parseWithErrorHandling as parseWithErrorHandling4 } from "@pagopa/io-wallet-utils";
|
|
559
|
+
import z7 from "zod";
|
|
560
|
+
|
|
426
561
|
// src/vp-token/parse-vp-token.ts
|
|
562
|
+
import { parseIfJson, parseWithErrorHandling as parseWithErrorHandling3 } from "@pagopa/io-wallet-utils";
|
|
427
563
|
function parseVpToken(vpToken) {
|
|
428
|
-
return
|
|
564
|
+
return parseWithErrorHandling3(
|
|
429
565
|
zVpToken,
|
|
430
566
|
parseIfJson(vpToken),
|
|
431
567
|
"Could not parse dcql vp_token. Expected an object where the values are encoded presentations"
|
|
@@ -445,16 +581,6 @@ function validateOpenid4vpAuthorizationResponsePayload(options) {
|
|
|
445
581
|
};
|
|
446
582
|
}
|
|
447
583
|
|
|
448
|
-
// src/authorization-response/z-authorization-response.ts
|
|
449
|
-
import z4 from "zod";
|
|
450
|
-
var zOpenid4vpAuthorizationResponse = z4.object({
|
|
451
|
-
state: z4.string(),
|
|
452
|
-
vp_token: zVpToken
|
|
453
|
-
});
|
|
454
|
-
var zOpenid4vpAuthorizationResponseResult = z4.object({
|
|
455
|
-
redirect_uri: z4.url().optional()
|
|
456
|
-
});
|
|
457
|
-
|
|
458
584
|
// src/jarm/verify-jarm-authorization-response.ts
|
|
459
585
|
import { jwtSignerFromJwt } from "@openid4vc/oauth2";
|
|
460
586
|
import {
|
|
@@ -557,6 +683,7 @@ async function verifyJarmAuthorizationResponse(options) {
|
|
|
557
683
|
let jarmAuthorizationResponse;
|
|
558
684
|
if (responseIsSigned) {
|
|
559
685
|
const { header: jwsProtectedHeader, payload: jwsPayload } = decodeJwt2({
|
|
686
|
+
errorMessagePrefix: "Error decoding JARM authorization response JWT:",
|
|
560
687
|
headerSchema: z6.object({ ...zJwtHeader2.shape, kid: z6.string() }),
|
|
561
688
|
jwt: decryptedRequestData.payload
|
|
562
689
|
});
|
|
@@ -614,7 +741,7 @@ async function verifyJarmAuthorizationResponse(options) {
|
|
|
614
741
|
// src/jarm/parse-jarm-authorization-response.ts
|
|
615
742
|
async function parseJarmAuthorizationResponse(options) {
|
|
616
743
|
const { authorizationRequestPayload, callbacks, jarmResponseJwt, now } = options;
|
|
617
|
-
const jarmAuthorizationResponseJwt =
|
|
744
|
+
const jarmAuthorizationResponseJwt = parseWithErrorHandling4(
|
|
618
745
|
z7.union([zCompactJwt2, zCompactJwe2]),
|
|
619
746
|
jarmResponseJwt,
|
|
620
747
|
"Invalid jarm authorization response jwt."
|
|
@@ -629,7 +756,7 @@ async function parseJarmAuthorizationResponse(options) {
|
|
|
629
756
|
headerSchema: zJarmHeader,
|
|
630
757
|
jwt: jarmAuthorizationResponseJwt
|
|
631
758
|
});
|
|
632
|
-
const authorizationResponsePayload =
|
|
759
|
+
const authorizationResponsePayload = parseWithErrorHandling4(
|
|
633
760
|
zOpenid4vpAuthorizationResponse,
|
|
634
761
|
verifiedJarmResponse.jarmAuthorizationResponse,
|
|
635
762
|
"Failed to parse openid4vp authorization response."
|
|
@@ -646,124 +773,7 @@ async function parseJarmAuthorizationResponse(options) {
|
|
|
646
773
|
};
|
|
647
774
|
}
|
|
648
775
|
|
|
649
|
-
// src/authorization-response/create-authorization-response.ts
|
|
650
|
-
async function createAuthorizationResponse(options) {
|
|
651
|
-
try {
|
|
652
|
-
const encryptionAlg = options.authorization_encrypted_response_alg ?? "ECDH-ES";
|
|
653
|
-
const encryptionEnc = options.authorization_encrypted_response_enc ?? "A256GCM";
|
|
654
|
-
const { requestObject } = options;
|
|
655
|
-
const clientMetadata = requestObject.client_metadata;
|
|
656
|
-
const clientIdPrefix = extractClientIdPrefix(requestObject.client_id);
|
|
657
|
-
if (clientIdPrefix === "x509_hash" /* X509_HASH */ && !clientMetadata) {
|
|
658
|
-
throw new CreateAuthorizationResponseError(
|
|
659
|
-
"clientMetadata is required when client_id uses x509_hash prefix"
|
|
660
|
-
);
|
|
661
|
-
}
|
|
662
|
-
const effectiveClientMetadata = clientIdPrefix === "openid_federation" /* OPENID_FEDERATION */ ? void 0 : clientMetadata;
|
|
663
|
-
const authorizationResponsePayload = {
|
|
664
|
-
state: requestObject.state,
|
|
665
|
-
vp_token: options.vp_token
|
|
666
|
-
};
|
|
667
|
-
const encryptionJwks = effectiveClientMetadata ? effectiveClientMetadata.jwks : options.rpJwks.jwks;
|
|
668
|
-
const encryptionJwk = extractEncryptionJwkFromJwks(encryptionJwks, {
|
|
669
|
-
supportedAlgValues: [encryptionAlg]
|
|
670
|
-
});
|
|
671
|
-
if (!encryptionJwk) {
|
|
672
|
-
throw new CreateAuthorizationResponseError(
|
|
673
|
-
"No encryption JWK found in metadata"
|
|
674
|
-
);
|
|
675
|
-
}
|
|
676
|
-
const encValuesSupported = effectiveClientMetadata?.encrypted_response_enc_values_supported ?? options.rpJwks.encrypted_response_enc_values_supported;
|
|
677
|
-
let enc;
|
|
678
|
-
if (encValuesSupported) {
|
|
679
|
-
if (options.authorization_encrypted_response_enc !== void 0) {
|
|
680
|
-
enc = encValuesSupported.find(
|
|
681
|
-
(e) => e === options.authorization_encrypted_response_enc
|
|
682
|
-
) ?? encValuesSupported[0] ?? options.authorization_encrypted_response_enc;
|
|
683
|
-
} else {
|
|
684
|
-
enc = encValuesSupported[0] ?? encryptionEnc;
|
|
685
|
-
}
|
|
686
|
-
} else {
|
|
687
|
-
enc = encryptionEnc;
|
|
688
|
-
}
|
|
689
|
-
const alg = encryptionJwk.alg ?? encryptionAlg;
|
|
690
|
-
const nonceBytes = await options.callbacks.generateRandom(32);
|
|
691
|
-
const jweEncryptor = {
|
|
692
|
-
alg,
|
|
693
|
-
apu: encodeToBase64Url(nonceBytes),
|
|
694
|
-
apv: encodeToBase64Url(requestObject.nonce),
|
|
695
|
-
enc,
|
|
696
|
-
method: "jwk",
|
|
697
|
-
publicJwk: encryptionJwk
|
|
698
|
-
};
|
|
699
|
-
const plaintext = JSON.stringify(authorizationResponsePayload);
|
|
700
|
-
const { encryptionJwk: usedJwk, jwe } = await options.callbacks.encryptJwe(
|
|
701
|
-
jweEncryptor,
|
|
702
|
-
plaintext
|
|
703
|
-
);
|
|
704
|
-
return {
|
|
705
|
-
authorizationResponsePayload,
|
|
706
|
-
jarm: {
|
|
707
|
-
encryptionJwk: usedJwk,
|
|
708
|
-
responseJwe: jwe
|
|
709
|
-
}
|
|
710
|
-
};
|
|
711
|
-
} catch (error) {
|
|
712
|
-
if (error instanceof CreateAuthorizationResponseError) {
|
|
713
|
-
throw error;
|
|
714
|
-
}
|
|
715
|
-
throw new CreateAuthorizationResponseError(
|
|
716
|
-
`Unexpected error during authorization response creation: ${error instanceof Error ? error.message : String(error)}`
|
|
717
|
-
);
|
|
718
|
-
}
|
|
719
|
-
}
|
|
720
|
-
|
|
721
|
-
// src/authorization-response/fetch-authorization-response.ts
|
|
722
|
-
import {
|
|
723
|
-
CONTENT_TYPES,
|
|
724
|
-
HEADERS,
|
|
725
|
-
UnexpectedStatusCodeError as UnexpectedStatusCodeError2,
|
|
726
|
-
ValidationError as ValidationError4,
|
|
727
|
-
createFetcher as createFetcher2,
|
|
728
|
-
hasStatusOrThrow as hasStatusOrThrow2,
|
|
729
|
-
parseWithErrorHandling as parseWithErrorHandling4
|
|
730
|
-
} from "@pagopa/io-wallet-utils";
|
|
731
|
-
async function fetchAuthorizationResponse(options) {
|
|
732
|
-
try {
|
|
733
|
-
const fetch = createFetcher2(options.callbacks.fetch);
|
|
734
|
-
const authorizationResponseResult = await fetch(
|
|
735
|
-
options.presentationResponseUri,
|
|
736
|
-
{
|
|
737
|
-
body: new URLSearchParams({
|
|
738
|
-
response: options.authorizationResponseJarm
|
|
739
|
-
}),
|
|
740
|
-
headers: {
|
|
741
|
-
[HEADERS.CONTENT_TYPE]: CONTENT_TYPES.FORM_URLENCODED
|
|
742
|
-
},
|
|
743
|
-
method: "POST"
|
|
744
|
-
}
|
|
745
|
-
);
|
|
746
|
-
await hasStatusOrThrow2(
|
|
747
|
-
200,
|
|
748
|
-
UnexpectedStatusCodeError2
|
|
749
|
-
)(authorizationResponseResult);
|
|
750
|
-
const authorizationResponseResultJson = await authorizationResponseResult.json();
|
|
751
|
-
return parseWithErrorHandling4(
|
|
752
|
-
zOpenid4vpAuthorizationResponseResult,
|
|
753
|
-
authorizationResponseResultJson
|
|
754
|
-
);
|
|
755
|
-
} catch (error) {
|
|
756
|
-
if (error instanceof UnexpectedStatusCodeError2 || error instanceof ValidationError4) {
|
|
757
|
-
throw error;
|
|
758
|
-
}
|
|
759
|
-
throw new FetchAuthorizationResponseError(
|
|
760
|
-
`Unexpected error sending authorization response: ${error instanceof Error ? error.message : String(error)}`
|
|
761
|
-
);
|
|
762
|
-
}
|
|
763
|
-
}
|
|
764
|
-
|
|
765
776
|
// src/authorization-response/parse-authorization-response.ts
|
|
766
|
-
import { parseWithErrorHandling as parseWithErrorHandling5 } from "@pagopa/io-wallet-utils";
|
|
767
777
|
async function parseAuthorizationResponse(options) {
|
|
768
778
|
const { authorizationRequestPayload, authorizationResponse, callbacks } = options;
|
|
769
779
|
if (authorizationResponse.response) {
|