@openid4vc/openid4vp 0.3.0-alpha-20250225204254 → 0.3.0-alpha-20250303091928
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 +74 -27
- package/dist/index.d.ts +74 -27
- package/dist/index.js +436 -267
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +370 -201
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -393,9 +393,19 @@ var zOpenid4vpAuthorizationRequest = import_zod7.z.object({
|
|
|
393
393
|
presentation_definition_uri: import_utils5.zHttpsUrl.optional(),
|
|
394
394
|
dcql_query: import_zod7.z.record(import_zod7.z.any()).optional(),
|
|
395
395
|
client_metadata: zClientMetadata.optional(),
|
|
396
|
+
client_metadata_uri: import_utils5.zHttpsUrl.optional(),
|
|
396
397
|
state: import_zod7.z.string().optional(),
|
|
397
398
|
transaction_data: import_zod7.z.array(import_zod7.z.string()).optional(),
|
|
398
|
-
trust_chain: import_zod7.z.unknown().optional()
|
|
399
|
+
trust_chain: import_zod7.z.unknown().optional(),
|
|
400
|
+
client_id_scheme: import_zod7.z.enum([
|
|
401
|
+
"pre-registered",
|
|
402
|
+
"redirect_uri",
|
|
403
|
+
"entity_id",
|
|
404
|
+
"did",
|
|
405
|
+
"verifier_attestation",
|
|
406
|
+
"x509_san_dns",
|
|
407
|
+
"x509_san_uri"
|
|
408
|
+
]).optional()
|
|
399
409
|
}).passthrough();
|
|
400
410
|
|
|
401
411
|
// src/authorization-request/z-authorization-request-dc-api.ts
|
|
@@ -412,21 +422,30 @@ var zOpenid4vpAuthorizationRequestDcApi = zOpenid4vpAuthorizationRequest.pick({
|
|
|
412
422
|
}).extend({
|
|
413
423
|
client_id: import_zod8.z.optional(import_zod8.z.string()),
|
|
414
424
|
expected_origins: import_zod8.z.array(import_zod8.z.string()).optional(),
|
|
415
|
-
response_mode: import_zod8.z.enum(["dc_api", "dc_api.jwt"])
|
|
425
|
+
response_mode: import_zod8.z.enum(["dc_api", "dc_api.jwt", "w3c_dc_api.jwt", "w3c_dc_api"]),
|
|
426
|
+
client_id_scheme: import_zod8.z.enum([
|
|
427
|
+
"pre-registered",
|
|
428
|
+
"redirect_uri",
|
|
429
|
+
"entity_id",
|
|
430
|
+
"did",
|
|
431
|
+
"verifier_attestation",
|
|
432
|
+
"x509_san_dns",
|
|
433
|
+
"x509_san_uri"
|
|
434
|
+
]).optional()
|
|
416
435
|
}).strip();
|
|
417
436
|
function isOpenid4vpAuthorizationRequestDcApi(request) {
|
|
418
|
-
return request.response_mode === "dc_api" || request.response_mode === "dc_api.jwt";
|
|
437
|
+
return request.response_mode === "dc_api" || request.response_mode === "dc_api.jwt" || request.response_mode === "w3c_dc_api.jwt" || request.response_mode === "w3c_dc_api";
|
|
419
438
|
}
|
|
420
439
|
|
|
421
440
|
// src/authorization-request/create-authorization-request.ts
|
|
422
441
|
async function createOpenid4vpAuthorizationRequest(options) {
|
|
423
|
-
const { jar, scheme = "openid4vp://",
|
|
442
|
+
const { jar, scheme = "openid4vp://", requestPayload, wallet, callbacks } = options;
|
|
424
443
|
let additionalJwtPayload;
|
|
425
444
|
let authRequestParams;
|
|
426
|
-
if (isOpenid4vpAuthorizationRequestDcApi(
|
|
445
|
+
if (isOpenid4vpAuthorizationRequestDcApi(requestPayload)) {
|
|
427
446
|
authRequestParams = (0, import_utils6.parseWithErrorHandling)(
|
|
428
447
|
zOpenid4vpAuthorizationRequestDcApi,
|
|
429
|
-
|
|
448
|
+
requestPayload,
|
|
430
449
|
"Invalid authorization request. Could not parse openid4vp dc_api authorization request."
|
|
431
450
|
);
|
|
432
451
|
if (jar && !authRequestParams.expected_origins) {
|
|
@@ -442,7 +461,7 @@ async function createOpenid4vpAuthorizationRequest(options) {
|
|
|
442
461
|
} else {
|
|
443
462
|
authRequestParams = (0, import_utils6.parseWithErrorHandling)(
|
|
444
463
|
zOpenid4vpAuthorizationRequest,
|
|
445
|
-
|
|
464
|
+
requestPayload,
|
|
446
465
|
"Invalid authorization request. Could not parse openid4vp authorization request."
|
|
447
466
|
);
|
|
448
467
|
validateOpenid4vpAuthorizationRequestPayload({ params: authRequestParams, walletVerificationOptions: wallet });
|
|
@@ -455,7 +474,7 @@ async function createOpenid4vpAuthorizationRequest(options) {
|
|
|
455
474
|
if (jar) {
|
|
456
475
|
const jarResult = await createJarAuthRequest({
|
|
457
476
|
...jar,
|
|
458
|
-
authRequestParams:
|
|
477
|
+
authRequestParams: requestPayload,
|
|
459
478
|
additionalJwtPayload,
|
|
460
479
|
callbacks
|
|
461
480
|
});
|
|
@@ -473,10 +492,10 @@ async function createOpenid4vpAuthorizationRequest(options) {
|
|
|
473
492
|
const url = new import_utils6.URL(scheme);
|
|
474
493
|
url.search = `?${new import_utils6.URLSearchParams([
|
|
475
494
|
...url.searchParams.entries(),
|
|
476
|
-
...(0, import_utils6.objectToQueryParams)(
|
|
495
|
+
...(0, import_utils6.objectToQueryParams)(requestPayload).entries()
|
|
477
496
|
]).toString()}`;
|
|
478
497
|
return {
|
|
479
|
-
authRequestObject:
|
|
498
|
+
authRequestObject: requestPayload,
|
|
480
499
|
authRequest: url.toString(),
|
|
481
500
|
jar: void 0
|
|
482
501
|
};
|
|
@@ -562,17 +581,82 @@ function parseOpenid4vpAuthorizationRequestPayload(options) {
|
|
|
562
581
|
}
|
|
563
582
|
|
|
564
583
|
// src/authorization-request/resolve-authorization-request.ts
|
|
565
|
-
var
|
|
566
|
-
var
|
|
567
|
-
var
|
|
584
|
+
var import_oauth219 = require("@openid4vc/oauth2");
|
|
585
|
+
var import_utils13 = require("@openid4vc/utils");
|
|
586
|
+
var import_zod15 = __toESM(require("zod"));
|
|
568
587
|
|
|
569
588
|
// src/client-identifier-scheme/parse-client-identifier-scheme.ts
|
|
589
|
+
var import_oauth213 = require("@openid4vc/oauth2");
|
|
590
|
+
|
|
591
|
+
// src/version.ts
|
|
570
592
|
var import_oauth212 = require("@openid4vc/oauth2");
|
|
593
|
+
function parseAuthorizationRequestVersion(request) {
|
|
594
|
+
const requirements = [];
|
|
595
|
+
const vp_formats = request.client_metadata?.vp_formats;
|
|
596
|
+
if (isOpenid4vpAuthorizationRequestDcApi(request) && (request.response_mode === "w3c_dc_api" || request.response_mode === "w3c_dc_api.jwt")) {
|
|
597
|
+
requirements.push(["<", 23]);
|
|
598
|
+
requirements.push([">=", 21]);
|
|
599
|
+
}
|
|
600
|
+
if (isOpenid4vpAuthorizationRequestDcApi(request) && request.response_mode === "dc_api" || request.response_mode === "dc_api.jwt") {
|
|
601
|
+
requirements.push([">=", 23]);
|
|
602
|
+
}
|
|
603
|
+
if (isOpenid4vpAuthorizationRequestDcApi(request) && (request.transaction_data || request.dcql_query)) {
|
|
604
|
+
requirements.push([">=", 23]);
|
|
605
|
+
}
|
|
606
|
+
if (request.dcql_query) {
|
|
607
|
+
requirements.push([">=", 22]);
|
|
608
|
+
}
|
|
609
|
+
if (request.transaction_data) {
|
|
610
|
+
requirements.push([">=", 22]);
|
|
611
|
+
}
|
|
612
|
+
if (request.client_id_scheme) {
|
|
613
|
+
requirements.push(["<", 22]);
|
|
614
|
+
}
|
|
615
|
+
if (request.client_id) {
|
|
616
|
+
const colonIndex = request.client_id.indexOf(":");
|
|
617
|
+
const schemePart = request.client_id.substring(0, colonIndex);
|
|
618
|
+
const parsedScheme = zClientIdScheme.safeParse(schemePart);
|
|
619
|
+
if (parsedScheme.success && parsedScheme.data !== "did" && parsedScheme.data !== "https") {
|
|
620
|
+
requirements.push([">=", 22]);
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
if (!request.client_id) {
|
|
624
|
+
requirements.push([">=", 21]);
|
|
625
|
+
}
|
|
626
|
+
if ("client_metadata_uri" in request) {
|
|
627
|
+
requirements.push(["<", 21]);
|
|
628
|
+
}
|
|
629
|
+
if (isOpenid4vpAuthorizationRequestDcApi(request)) {
|
|
630
|
+
requirements.push([">=", 21]);
|
|
631
|
+
}
|
|
632
|
+
if ("request_uri_method" in request || "wallet_nonce" in request) {
|
|
633
|
+
requirements.push([">=", 21]);
|
|
634
|
+
}
|
|
635
|
+
if (request.client_id_scheme === "verifier_attestation") {
|
|
636
|
+
requirements.push([">=", 20]);
|
|
637
|
+
}
|
|
638
|
+
if (request.client_id_scheme === "x509_san_dns" || request.client_id_scheme === "x509_san_uri") {
|
|
639
|
+
requirements.push([">=", 19]);
|
|
640
|
+
}
|
|
641
|
+
const lessThanVersions = requirements.filter(([operator]) => operator === "<").map(([_, version]) => version);
|
|
642
|
+
const greaterThanVersions = requirements.filter(([operator]) => operator === ">=").map(([_, version]) => version);
|
|
643
|
+
const highestPossibleVersion = lessThanVersions.length > 0 ? Math.max(Math.min(...lessThanVersions) - 1, 18) : 24;
|
|
644
|
+
const lowestRequiredVersion = greaterThanVersions.length > 0 ? Math.max(...greaterThanVersions) : 18;
|
|
645
|
+
if (lowestRequiredVersion > highestPossibleVersion) {
|
|
646
|
+
throw new import_oauth212.Oauth2ServerErrorResponseError({
|
|
647
|
+
error: import_oauth212.Oauth2ErrorCodes.InvalidRequest,
|
|
648
|
+
error_description: "Could not infer openid4vp version from the openid4vp request payload."
|
|
649
|
+
});
|
|
650
|
+
}
|
|
651
|
+
return highestPossibleVersion;
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
// src/client-identifier-scheme/parse-client-identifier-scheme.ts
|
|
571
655
|
function getClientId(options) {
|
|
572
656
|
if (isOpenid4vpAuthorizationRequestDcApi(options.request)) {
|
|
573
657
|
if (!options.origin) {
|
|
574
|
-
throw new
|
|
575
|
-
error:
|
|
658
|
+
throw new import_oauth213.Oauth2ServerErrorResponseError({
|
|
659
|
+
error: import_oauth213.Oauth2ErrorCodes.InvalidRequest,
|
|
576
660
|
error_description: "Failed to parse client identifier. 'origin' is required for requests with response_mode 'dc_api' and 'dc_api.jwt'"
|
|
577
661
|
});
|
|
578
662
|
}
|
|
@@ -581,10 +665,48 @@ function getClientId(options) {
|
|
|
581
665
|
}
|
|
582
666
|
return options.request.client_id;
|
|
583
667
|
}
|
|
668
|
+
function getLegacyClientId(options) {
|
|
669
|
+
const legacyClientIdScheme = options.request.client_id_scheme ?? "pre-registered";
|
|
670
|
+
let clientIdScheme;
|
|
671
|
+
if (legacyClientIdScheme === "entity_id") {
|
|
672
|
+
clientIdScheme = "https";
|
|
673
|
+
} else {
|
|
674
|
+
clientIdScheme = legacyClientIdScheme;
|
|
675
|
+
}
|
|
676
|
+
if (isOpenid4vpAuthorizationRequestDcApi(options.request)) {
|
|
677
|
+
if (!options.origin) {
|
|
678
|
+
throw new import_oauth213.Oauth2ServerErrorResponseError({
|
|
679
|
+
error: import_oauth213.Oauth2ErrorCodes.InvalidRequest,
|
|
680
|
+
error_description: "Failed to parse client identifier. 'origin' is required for requests with response_mode 'dc_api' and 'dc_api.jwt'"
|
|
681
|
+
});
|
|
682
|
+
}
|
|
683
|
+
if (!options.jar || !options.request.client_id) return `web-origin:${options.origin}`;
|
|
684
|
+
return `${clientIdScheme}:${options.request.client_id}`;
|
|
685
|
+
}
|
|
686
|
+
if (clientIdScheme === "https" || clientIdScheme === "did") {
|
|
687
|
+
return options.request.client_id;
|
|
688
|
+
}
|
|
689
|
+
if (clientIdScheme === "pre-registered") {
|
|
690
|
+
return options.request.client_id;
|
|
691
|
+
}
|
|
692
|
+
return `${clientIdScheme}:${options.request.client_id}`;
|
|
693
|
+
}
|
|
584
694
|
function parseClientIdentifier(options, parserConfig) {
|
|
585
695
|
const { request, jar } = options;
|
|
696
|
+
const version = parseAuthorizationRequestVersion(request);
|
|
697
|
+
if (version < 22) {
|
|
698
|
+
const legacyClientIdScheme = request.client_id_scheme ?? "pre-registered";
|
|
699
|
+
let clientIdSchem;
|
|
700
|
+
if (legacyClientIdScheme) {
|
|
701
|
+
if (legacyClientIdScheme === "entity_id") {
|
|
702
|
+
clientIdSchem = "https";
|
|
703
|
+
} else {
|
|
704
|
+
clientIdSchem = legacyClientIdScheme;
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
}
|
|
586
708
|
const isDcApiRequest = isOpenid4vpAuthorizationRequestDcApi(request);
|
|
587
|
-
const clientId = getClientId(options);
|
|
709
|
+
const clientId = version < 22 ? getLegacyClientId(options) : getClientId(options);
|
|
588
710
|
const parserConfigWithDefaults = {
|
|
589
711
|
supportedSchemes: parserConfig?.supportedSchemes || Object.values(zClientIdScheme.options)
|
|
590
712
|
};
|
|
@@ -600,22 +722,22 @@ function parseClientIdentifier(options, parserConfig) {
|
|
|
600
722
|
const schemePart = clientId.substring(0, colonIndex);
|
|
601
723
|
const identifierPart = clientId.substring(colonIndex + 1);
|
|
602
724
|
if (!parserConfigWithDefaults.supportedSchemes.includes(schemePart)) {
|
|
603
|
-
throw new
|
|
604
|
-
error:
|
|
725
|
+
throw new import_oauth213.Oauth2ServerErrorResponseError({
|
|
726
|
+
error: import_oauth213.Oauth2ErrorCodes.InvalidRequest,
|
|
605
727
|
error_description: `Unsupported client identifier scheme. ${schemePart} is not supported.`
|
|
606
728
|
});
|
|
607
729
|
}
|
|
608
730
|
const scheme = schemePart;
|
|
609
731
|
if (scheme === "https") {
|
|
610
732
|
if (isDcApiRequest) {
|
|
611
|
-
throw new
|
|
612
|
-
error:
|
|
733
|
+
throw new import_oauth213.Oauth2ServerErrorResponseError({
|
|
734
|
+
error: import_oauth213.Oauth2ErrorCodes.InvalidRequest,
|
|
613
735
|
error_description: `The client identifier scheme 'https' is not supported when using the dc_api response mode.`
|
|
614
736
|
});
|
|
615
737
|
}
|
|
616
|
-
if (!clientId.startsWith("https://") && !((0,
|
|
617
|
-
throw new
|
|
618
|
-
error:
|
|
738
|
+
if (!clientId.startsWith("https://") && !((0, import_oauth213.getGlobalConfig)().allowInsecureUrls && clientId.startsWith("http://"))) {
|
|
739
|
+
throw new import_oauth213.Oauth2ServerErrorResponseError({
|
|
740
|
+
error: import_oauth213.Oauth2ErrorCodes.InvalidRequest,
|
|
619
741
|
error_description: "Invalid client identifier. Client identifier must start with https:// or http:// if allowInsecureUrls is true."
|
|
620
742
|
});
|
|
621
743
|
}
|
|
@@ -628,14 +750,14 @@ function parseClientIdentifier(options, parserConfig) {
|
|
|
628
750
|
}
|
|
629
751
|
if (scheme === "redirect_uri") {
|
|
630
752
|
if (jar) {
|
|
631
|
-
throw new
|
|
632
|
-
error:
|
|
753
|
+
throw new import_oauth213.Oauth2ServerErrorResponseError({
|
|
754
|
+
error: import_oauth213.Oauth2ErrorCodes.InvalidRequest,
|
|
633
755
|
error_description: 'Using client identifier scheme "redirect_uri" the request MUST NOT be signed.'
|
|
634
756
|
});
|
|
635
757
|
}
|
|
636
758
|
if (isOpenid4vpAuthorizationRequestDcApi(request)) {
|
|
637
|
-
throw new
|
|
638
|
-
error:
|
|
759
|
+
throw new import_oauth213.Oauth2ServerErrorResponseError({
|
|
760
|
+
error: import_oauth213.Oauth2ErrorCodes.InvalidRequest,
|
|
639
761
|
error_description: `The client identifier scheme 'redirect_uri' is not supported when using the dc_api response mode.`
|
|
640
762
|
});
|
|
641
763
|
}
|
|
@@ -648,26 +770,26 @@ function parseClientIdentifier(options, parserConfig) {
|
|
|
648
770
|
}
|
|
649
771
|
if (scheme === "did") {
|
|
650
772
|
if (!jar) {
|
|
651
|
-
throw new
|
|
652
|
-
error:
|
|
773
|
+
throw new import_oauth213.Oauth2ServerErrorResponseError({
|
|
774
|
+
error: import_oauth213.Oauth2ErrorCodes.InvalidRequest,
|
|
653
775
|
error_description: 'Using client identifier scheme "did" requires a signed JAR request.'
|
|
654
776
|
});
|
|
655
777
|
}
|
|
656
778
|
if (!clientId.startsWith("did:")) {
|
|
657
|
-
throw new
|
|
658
|
-
error:
|
|
779
|
+
throw new import_oauth213.Oauth2ServerErrorResponseError({
|
|
780
|
+
error: import_oauth213.Oauth2ErrorCodes.InvalidRequest,
|
|
659
781
|
error_description: "Invalid client identifier. Client identifier must start with 'did:'"
|
|
660
782
|
});
|
|
661
783
|
}
|
|
662
784
|
if (!jar.signer.publicJwk.kid) {
|
|
663
|
-
throw new
|
|
664
|
-
error:
|
|
785
|
+
throw new import_oauth213.Oauth2ServerErrorResponseError({
|
|
786
|
+
error: import_oauth213.Oauth2ErrorCodes.InvalidRequest,
|
|
665
787
|
error_description: `Missing required 'kid' for client identifier scheme: did`
|
|
666
788
|
});
|
|
667
789
|
}
|
|
668
790
|
if (!jar.signer.publicJwk.kid?.startsWith(clientId)) {
|
|
669
|
-
throw new
|
|
670
|
-
error:
|
|
791
|
+
throw new import_oauth213.Oauth2ServerErrorResponseError({
|
|
792
|
+
error: import_oauth213.Oauth2ErrorCodes.InvalidRequest,
|
|
671
793
|
error_description: 'With client identifier scheme "did" the JAR request must be signed by the same DID as the client identifier.'
|
|
672
794
|
});
|
|
673
795
|
}
|
|
@@ -680,22 +802,22 @@ function parseClientIdentifier(options, parserConfig) {
|
|
|
680
802
|
}
|
|
681
803
|
if (scheme === "x509_san_dns" || scheme === "x509_san_uri") {
|
|
682
804
|
if (!jar) {
|
|
683
|
-
throw new
|
|
684
|
-
error:
|
|
805
|
+
throw new import_oauth213.Oauth2ServerErrorResponseError({
|
|
806
|
+
error: import_oauth213.Oauth2ErrorCodes.InvalidRequest,
|
|
685
807
|
error_description: 'Using client identifier scheme "x509_san_dns" or "x509_san_uri" requires a signed JAR request.'
|
|
686
808
|
});
|
|
687
809
|
}
|
|
688
810
|
if (jar.signer.method !== "x5c") {
|
|
689
|
-
throw new
|
|
690
|
-
error:
|
|
811
|
+
throw new import_oauth213.Oauth2ServerErrorResponseError({
|
|
812
|
+
error: import_oauth213.Oauth2ErrorCodes.InvalidRequest,
|
|
691
813
|
error_description: "Something went wrong. The JWT signer method is not x5c but the client identifier scheme is x509_san_dns."
|
|
692
814
|
});
|
|
693
815
|
}
|
|
694
816
|
if (scheme === "x509_san_dns") {
|
|
695
817
|
if (!options.callbacks.getX509CertificateMetadata) {
|
|
696
|
-
throw new
|
|
818
|
+
throw new import_oauth213.Oauth2ServerErrorResponseError(
|
|
697
819
|
{
|
|
698
|
-
error:
|
|
820
|
+
error: import_oauth213.Oauth2ErrorCodes.ServerError
|
|
699
821
|
},
|
|
700
822
|
{
|
|
701
823
|
internalMessage: "Missing required 'getX509CertificateMetadata' callback for verification of 'x509_san_dns' client id scheme"
|
|
@@ -704,25 +826,25 @@ function parseClientIdentifier(options, parserConfig) {
|
|
|
704
826
|
}
|
|
705
827
|
const { sanDnsNames } = options.callbacks.getX509CertificateMetadata(jar.signer.x5c[0]);
|
|
706
828
|
if (!sanDnsNames.includes(identifierPart)) {
|
|
707
|
-
throw new
|
|
708
|
-
error:
|
|
709
|
-
error_description:
|
|
829
|
+
throw new import_oauth213.Oauth2ServerErrorResponseError({
|
|
830
|
+
error: import_oauth213.Oauth2ErrorCodes.InvalidRequest,
|
|
831
|
+
error_description: `Invalid client identifier. One of the leaf certificates san dns names [${sanDnsNames.join(", ")}] must match the client identifier '${identifierPart}'. `
|
|
710
832
|
});
|
|
711
833
|
}
|
|
712
834
|
if (!isOpenid4vpAuthorizationRequestDcApi(request)) {
|
|
713
835
|
const uri = request.redirect_uri ?? request.response_uri;
|
|
714
836
|
if (!uri || getDomainFromUrl(uri) !== identifierPart) {
|
|
715
|
-
throw new
|
|
716
|
-
error:
|
|
837
|
+
throw new import_oauth213.Oauth2ServerErrorResponseError({
|
|
838
|
+
error: import_oauth213.Oauth2ErrorCodes.InvalidRequest,
|
|
717
839
|
error_description: "Invalid client identifier. The fully qualified domain name of the redirect_uri value MUST match the Client Identifier without the prefix x509_san_dns."
|
|
718
840
|
});
|
|
719
841
|
}
|
|
720
842
|
}
|
|
721
843
|
} else if (scheme === "x509_san_uri") {
|
|
722
844
|
if (!options.callbacks.getX509CertificateMetadata) {
|
|
723
|
-
throw new
|
|
845
|
+
throw new import_oauth213.Oauth2ServerErrorResponseError(
|
|
724
846
|
{
|
|
725
|
-
error:
|
|
847
|
+
error: import_oauth213.Oauth2ErrorCodes.ServerError
|
|
726
848
|
},
|
|
727
849
|
{
|
|
728
850
|
internalMessage: "Missing required 'getX509CertificateMetadata' callback for verification of 'x509_san_uri' client id scheme"
|
|
@@ -731,16 +853,16 @@ function parseClientIdentifier(options, parserConfig) {
|
|
|
731
853
|
}
|
|
732
854
|
const { sanUriNames } = options.callbacks.getX509CertificateMetadata(jar.signer.x5c[0]);
|
|
733
855
|
if (!sanUriNames.includes(identifierPart)) {
|
|
734
|
-
throw new
|
|
735
|
-
error:
|
|
736
|
-
error_description:
|
|
856
|
+
throw new import_oauth213.Oauth2ServerErrorResponseError({
|
|
857
|
+
error: import_oauth213.Oauth2ErrorCodes.InvalidRequest,
|
|
858
|
+
error_description: `Invalid client identifier. One of the leaf certificates san uri names [${sanUriNames.join(", ")}] must match the client identifier '${identifierPart}'.`
|
|
737
859
|
});
|
|
738
860
|
}
|
|
739
861
|
if (!isOpenid4vpAuthorizationRequestDcApi(request)) {
|
|
740
862
|
const uri = request.redirect_uri || request.response_uri;
|
|
741
863
|
if (!uri || uri !== identifierPart) {
|
|
742
|
-
throw new
|
|
743
|
-
error:
|
|
864
|
+
throw new import_oauth213.Oauth2ServerErrorResponseError({
|
|
865
|
+
error: import_oauth213.Oauth2ErrorCodes.InvalidRequest,
|
|
744
866
|
error_description: "The redirect_uri value MUST match the Client Identifier without the prefix x509_san_uri"
|
|
745
867
|
});
|
|
746
868
|
}
|
|
@@ -763,8 +885,8 @@ function parseClientIdentifier(options, parserConfig) {
|
|
|
763
885
|
}
|
|
764
886
|
if (scheme === "verifier_attestation") {
|
|
765
887
|
if (!jar) {
|
|
766
|
-
throw new
|
|
767
|
-
error:
|
|
888
|
+
throw new import_oauth213.Oauth2ServerErrorResponseError({
|
|
889
|
+
error: import_oauth213.Oauth2ErrorCodes.InvalidRequest,
|
|
768
890
|
error_description: 'Using client identifier scheme "verifier_attestation" requires a signed JAR request.'
|
|
769
891
|
});
|
|
770
892
|
}
|
|
@@ -781,57 +903,97 @@ function getDomainFromUrl(url) {
|
|
|
781
903
|
const domain = url.split("://")[1].split(regex)[0];
|
|
782
904
|
return domain;
|
|
783
905
|
} catch (error) {
|
|
784
|
-
throw new
|
|
785
|
-
error:
|
|
906
|
+
throw new import_oauth213.Oauth2ServerErrorResponseError({
|
|
907
|
+
error: import_oauth213.Oauth2ErrorCodes.ServerError,
|
|
786
908
|
error_description: `Url '${url}' is not a valid URL`
|
|
787
909
|
});
|
|
788
910
|
}
|
|
789
911
|
}
|
|
790
912
|
|
|
913
|
+
// src/fetch-client-metadata.ts
|
|
914
|
+
var import_oauth214 = require("@openid4vc/oauth2");
|
|
915
|
+
var import_utils10 = require("@openid4vc/utils");
|
|
916
|
+
|
|
917
|
+
// src/models/z-wallet-metadata.ts
|
|
918
|
+
var import_zod11 = require("zod");
|
|
919
|
+
var zWalletMetadata = import_zod11.z.object({
|
|
920
|
+
presentation_definition_uri_supported: import_zod11.z.optional(import_zod11.z.boolean()),
|
|
921
|
+
vp_formats_supported: zVpFormatsSupported,
|
|
922
|
+
client_id_schemes_supported: import_zod11.z.optional(import_zod11.z.array(zClientIdScheme)),
|
|
923
|
+
request_object_signing_alg_values_supported: import_zod11.z.optional(import_zod11.z.array(import_zod11.z.string())),
|
|
924
|
+
authorization_encryption_alg_values_supported: import_zod11.z.optional(import_zod11.z.array(import_zod11.z.string())),
|
|
925
|
+
authorization_encryption_enc_values_supported: import_zod11.z.optional(import_zod11.z.array(import_zod11.z.string()))
|
|
926
|
+
});
|
|
927
|
+
|
|
928
|
+
// src/fetch-client-metadata.ts
|
|
929
|
+
async function fetchClientMetadata(options) {
|
|
930
|
+
const { fetch, clientMetadataUri } = options;
|
|
931
|
+
const fetcher = (0, import_utils10.createZodFetcher)(fetch);
|
|
932
|
+
const { result, response } = await fetcher(zWalletMetadata, import_utils10.ContentType.Json, clientMetadataUri, {
|
|
933
|
+
method: "GET",
|
|
934
|
+
headers: {
|
|
935
|
+
Accept: import_utils10.ContentType.Json
|
|
936
|
+
}
|
|
937
|
+
});
|
|
938
|
+
if (!response.ok) {
|
|
939
|
+
throw new import_oauth214.Oauth2ServerErrorResponseError({
|
|
940
|
+
error_description: `Fetching client metadata from '${clientMetadataUri}' failed with status code '${response.status}'.`,
|
|
941
|
+
error: import_oauth214.Oauth2ErrorCodes.InvalidRequestUri
|
|
942
|
+
});
|
|
943
|
+
}
|
|
944
|
+
if (!result || !result.success) {
|
|
945
|
+
throw new import_oauth214.Oauth2ServerErrorResponseError({
|
|
946
|
+
error_description: `Parsing client metadata from '${clientMetadataUri}' failed.`,
|
|
947
|
+
error: import_oauth214.Oauth2ErrorCodes.InvalidRequestObject
|
|
948
|
+
});
|
|
949
|
+
}
|
|
950
|
+
return result.data;
|
|
951
|
+
}
|
|
952
|
+
|
|
791
953
|
// src/jar/handle-jar-request/verify-jar-request.ts
|
|
792
|
-
var
|
|
954
|
+
var import_oauth217 = require("@openid4vc/oauth2");
|
|
793
955
|
|
|
794
956
|
// src/jar/jar-request-object/fetch-jar-request-object.ts
|
|
795
|
-
var
|
|
796
|
-
var
|
|
797
|
-
var
|
|
957
|
+
var import_oauth215 = require("@openid4vc/oauth2");
|
|
958
|
+
var import_utils11 = require("@openid4vc/utils");
|
|
959
|
+
var import_zod12 = require("zod");
|
|
798
960
|
async function fetchJarRequestObject(options) {
|
|
799
961
|
const { requestUri, clientIdentifierScheme, method, wallet, fetch } = options;
|
|
800
|
-
const fetcher = (0,
|
|
962
|
+
const fetcher = (0, import_utils11.createZodFetcher)(fetch);
|
|
801
963
|
let requestBody = wallet.metadata ? { wallet_metadata: wallet.metadata, wallet_nonce: wallet.nonce } : void 0;
|
|
802
964
|
if (requestBody?.wallet_metadata?.request_object_signing_alg_values_supported && clientIdentifierScheme === "redirect_uri") {
|
|
803
965
|
const { request_object_signing_alg_values_supported, ...rest } = requestBody.wallet_metadata;
|
|
804
966
|
requestBody = { ...requestBody, wallet_metadata: { ...rest } };
|
|
805
967
|
}
|
|
806
|
-
const { result, response } = await fetcher(
|
|
968
|
+
const { result, response } = await fetcher(import_zod12.z.string(), import_utils11.ContentType.OAuthRequestObjectJwt, requestUri, {
|
|
807
969
|
method,
|
|
808
970
|
headers: {
|
|
809
|
-
Accept: `${
|
|
810
|
-
"Content-Type":
|
|
971
|
+
Accept: `${import_utils11.ContentType.OAuthRequestObjectJwt}, ${import_utils11.ContentType.Jwt};q=0.9`,
|
|
972
|
+
"Content-Type": import_utils11.ContentType.XWwwFormUrlencoded
|
|
811
973
|
},
|
|
812
|
-
body: method === "POST" ? (0,
|
|
974
|
+
body: method === "POST" ? (0, import_utils11.objectToQueryParams)(wallet.metadata ?? {}) : void 0
|
|
813
975
|
});
|
|
814
976
|
if (!response.ok) {
|
|
815
|
-
throw new
|
|
977
|
+
throw new import_oauth215.Oauth2ServerErrorResponseError({
|
|
816
978
|
error_description: `Fetching request_object from request_uri '${requestUri}' failed with status code '${response.status}'.`,
|
|
817
|
-
error:
|
|
979
|
+
error: import_oauth215.Oauth2ErrorCodes.InvalidRequestUri
|
|
818
980
|
});
|
|
819
981
|
}
|
|
820
982
|
if (!result || !result.success) {
|
|
821
|
-
throw new
|
|
983
|
+
throw new import_oauth215.Oauth2ServerErrorResponseError({
|
|
822
984
|
error_description: `Parsing request_object from request_uri '${requestUri}' failed.`,
|
|
823
|
-
error:
|
|
985
|
+
error: import_oauth215.Oauth2ErrorCodes.InvalidRequestObject
|
|
824
986
|
});
|
|
825
987
|
}
|
|
826
988
|
return result.data;
|
|
827
989
|
}
|
|
828
990
|
|
|
829
991
|
// src/jar/jar-request-object/z-jar-request-object.ts
|
|
830
|
-
var
|
|
831
|
-
var
|
|
832
|
-
var zJarRequestObjectPayload =
|
|
833
|
-
...
|
|
834
|
-
client_id:
|
|
992
|
+
var import_oauth216 = require("@openid4vc/oauth2");
|
|
993
|
+
var import_zod13 = require("zod");
|
|
994
|
+
var zJarRequestObjectPayload = import_zod13.z.object({
|
|
995
|
+
...import_oauth216.zJwtPayload.shape,
|
|
996
|
+
client_id: import_zod13.z.string()
|
|
835
997
|
}).passthrough();
|
|
836
998
|
|
|
837
999
|
// src/jar/handle-jar-request/verify-jar-request.ts
|
|
@@ -842,8 +1004,8 @@ async function verifyJarRequest(options) {
|
|
|
842
1004
|
const clientIdentifierScheme = jarRequestParams.client_id ? zClientIdScheme.parse(jarRequestParams.client_id.split(":")[0]) : "web-origin";
|
|
843
1005
|
const method = jarRequestParams.request_uri_method ?? "GET";
|
|
844
1006
|
if (method !== "GET" && method !== "POST") {
|
|
845
|
-
throw new
|
|
846
|
-
error:
|
|
1007
|
+
throw new import_oauth217.Oauth2ServerErrorResponseError({
|
|
1008
|
+
error: import_oauth217.Oauth2ErrorCodes.InvalidRequestUriMethod,
|
|
847
1009
|
error_description: "Invalid request_uri_method. Must be GET or POST."
|
|
848
1010
|
});
|
|
849
1011
|
}
|
|
@@ -853,12 +1015,12 @@ async function verifyJarRequest(options) {
|
|
|
853
1015
|
method,
|
|
854
1016
|
wallet
|
|
855
1017
|
});
|
|
856
|
-
const requestObjectIsEncrypted =
|
|
1018
|
+
const requestObjectIsEncrypted = import_oauth217.zCompactJwe.safeParse(requestObject).success;
|
|
857
1019
|
const { decryptionJwk, payload: decryptedRequestObject } = requestObjectIsEncrypted ? await decryptJarRequest({ jwe: requestObject, callbacks }) : { payload: requestObject, decryptionJwk: void 0 };
|
|
858
|
-
const requestIsSigned =
|
|
1020
|
+
const requestIsSigned = import_oauth217.zCompactJwt.safeParse(decryptedRequestObject).success;
|
|
859
1021
|
if (!requestIsSigned) {
|
|
860
|
-
throw new
|
|
861
|
-
error:
|
|
1022
|
+
throw new import_oauth217.Oauth2ServerErrorResponseError({
|
|
1023
|
+
error: import_oauth217.Oauth2ErrorCodes.InvalidRequestObject,
|
|
862
1024
|
error_description: "Jar Request Object is not a valid JWS."
|
|
863
1025
|
});
|
|
864
1026
|
}
|
|
@@ -867,14 +1029,14 @@ async function verifyJarRequest(options) {
|
|
|
867
1029
|
callbacks
|
|
868
1030
|
});
|
|
869
1031
|
if (!authRequestParams.client_id) {
|
|
870
|
-
throw new
|
|
871
|
-
error:
|
|
1032
|
+
throw new import_oauth217.Oauth2ServerErrorResponseError({
|
|
1033
|
+
error: import_oauth217.Oauth2ErrorCodes.InvalidRequestObject,
|
|
872
1034
|
error_description: 'Jar Request Object is missing the required "client_id" field.'
|
|
873
1035
|
});
|
|
874
1036
|
}
|
|
875
1037
|
if (jarRequestParams.client_id !== authRequestParams.client_id) {
|
|
876
|
-
throw new
|
|
877
|
-
error:
|
|
1038
|
+
throw new import_oauth217.Oauth2ServerErrorResponseError({
|
|
1039
|
+
error: import_oauth217.Oauth2ErrorCodes.InvalidRequest,
|
|
878
1040
|
error_description: "client_id does not match the request object client_id."
|
|
879
1041
|
});
|
|
880
1042
|
}
|
|
@@ -887,16 +1049,16 @@ async function verifyJarRequest(options) {
|
|
|
887
1049
|
}
|
|
888
1050
|
async function decryptJarRequest(options) {
|
|
889
1051
|
const { jwe, callbacks } = options;
|
|
890
|
-
const { header } = (0,
|
|
1052
|
+
const { header } = (0, import_oauth217.decodeJwt)({ jwt: jwe });
|
|
891
1053
|
if (!header.kid) {
|
|
892
|
-
throw new
|
|
893
|
-
error:
|
|
1054
|
+
throw new import_oauth217.Oauth2ServerErrorResponseError({
|
|
1055
|
+
error: import_oauth217.Oauth2ErrorCodes.InvalidRequestObject,
|
|
894
1056
|
error_description: 'Jar JWE is missing the protected header field "kid".'
|
|
895
1057
|
});
|
|
896
1058
|
}
|
|
897
1059
|
const decryptionResult = await callbacks.decryptJwe(jwe);
|
|
898
1060
|
if (!decryptionResult.decrypted) {
|
|
899
|
-
throw new
|
|
1061
|
+
throw new import_oauth217.Oauth2ServerErrorResponseError({
|
|
900
1062
|
error: "invalid_request_object",
|
|
901
1063
|
error_description: "Failed to decrypt jar request object."
|
|
902
1064
|
});
|
|
@@ -905,39 +1067,46 @@ async function decryptJarRequest(options) {
|
|
|
905
1067
|
}
|
|
906
1068
|
async function verifyJarRequestObject(options) {
|
|
907
1069
|
const { decryptedRequestObject, callbacks } = options;
|
|
908
|
-
const jwt = (0,
|
|
909
|
-
const jwtSigner = (0,
|
|
910
|
-
const { signer } = await (0,
|
|
1070
|
+
const jwt = (0, import_oauth217.decodeJwt)({ jwt: decryptedRequestObject, payloadSchema: zJarRequestObjectPayload });
|
|
1071
|
+
const jwtSigner = (0, import_oauth217.jwtSignerFromJwt)(jwt);
|
|
1072
|
+
const { signer } = await (0, import_oauth217.verifyJwt)({
|
|
911
1073
|
verifyJwtCallback: callbacks.verifyJwt,
|
|
912
1074
|
compact: decryptedRequestObject,
|
|
913
1075
|
header: jwt.header,
|
|
914
1076
|
payload: jwt.payload,
|
|
915
1077
|
signer: jwtSigner
|
|
916
1078
|
});
|
|
1079
|
+
const version = parseAuthorizationRequestVersion(jwt.payload);
|
|
1080
|
+
if (jwt.header.typ !== "oauth-authz-req+jwt" && version >= 24) {
|
|
1081
|
+
throw new import_oauth217.Oauth2ServerErrorResponseError({
|
|
1082
|
+
error: import_oauth217.Oauth2ErrorCodes.InvalidRequestObject,
|
|
1083
|
+
error_description: `Invalid Jar Request Object typ header. Expected "oauth-authz-req+jwt", received "${jwt.header.typ}".`
|
|
1084
|
+
});
|
|
1085
|
+
}
|
|
917
1086
|
return { authRequestParams: jwt.payload, signer };
|
|
918
1087
|
}
|
|
919
1088
|
|
|
920
1089
|
// src/transaction-data/parse-transaction-data.ts
|
|
921
|
-
var
|
|
922
|
-
var
|
|
1090
|
+
var import_oauth218 = require("@openid4vc/oauth2");
|
|
1091
|
+
var import_utils12 = require("@openid4vc/utils");
|
|
923
1092
|
|
|
924
1093
|
// src/transaction-data/z-transaction-data.ts
|
|
925
|
-
var
|
|
926
|
-
var zTransactionEntry =
|
|
927
|
-
type:
|
|
928
|
-
credential_ids:
|
|
929
|
-
transaction_data_hashes_alg:
|
|
1094
|
+
var import_zod14 = require("zod");
|
|
1095
|
+
var zTransactionEntry = import_zod14.z.object({
|
|
1096
|
+
type: import_zod14.z.string(),
|
|
1097
|
+
credential_ids: import_zod14.z.array(import_zod14.z.string()).min(1),
|
|
1098
|
+
transaction_data_hashes_alg: import_zod14.z.array(import_zod14.z.string()).optional()
|
|
930
1099
|
});
|
|
931
|
-
var zTransactionData =
|
|
1100
|
+
var zTransactionData = import_zod14.z.array(zTransactionEntry);
|
|
932
1101
|
|
|
933
1102
|
// src/transaction-data/parse-transaction-data.ts
|
|
934
1103
|
function parseTransactionData(options) {
|
|
935
1104
|
const { transactionData } = options;
|
|
936
|
-
const decoded = transactionData.map((tdEntry) => (0,
|
|
1105
|
+
const decoded = transactionData.map((tdEntry) => (0, import_utils12.parseIfJson)((0, import_utils12.encodeToUtf8String)((0, import_utils12.decodeBase64)(tdEntry))));
|
|
937
1106
|
const parsedResult = zTransactionData.safeParse(decoded);
|
|
938
1107
|
if (!parsedResult.success) {
|
|
939
|
-
throw new
|
|
940
|
-
error:
|
|
1108
|
+
throw new import_oauth218.Oauth2ServerErrorResponseError({
|
|
1109
|
+
error: import_oauth218.Oauth2ErrorCodes.InvalidTransactionData,
|
|
941
1110
|
error_description: "Failed to parse transaction data."
|
|
942
1111
|
});
|
|
943
1112
|
}
|
|
@@ -946,18 +1115,18 @@ function parseTransactionData(options) {
|
|
|
946
1115
|
|
|
947
1116
|
// src/authorization-request/resolve-authorization-request.ts
|
|
948
1117
|
async function resolveOpenid4vpAuthorizationRequest(options) {
|
|
949
|
-
const {
|
|
1118
|
+
const { requestPayload, wallet, callbacks, origin, omitOriginValidation } = options;
|
|
950
1119
|
let authRequestPayload;
|
|
951
|
-
const parsed = (0,
|
|
952
|
-
|
|
953
|
-
|
|
1120
|
+
const parsed = (0, import_utils13.parseWithErrorHandling)(
|
|
1121
|
+
import_zod15.default.union([zOpenid4vpAuthorizationRequestDcApi, zOpenid4vpAuthorizationRequest, zJarAuthRequest]),
|
|
1122
|
+
requestPayload,
|
|
954
1123
|
"Invalid authorization request. Could not parse openid4vp authorization request as openid4vp or jar auth request."
|
|
955
1124
|
);
|
|
956
1125
|
let jar;
|
|
957
1126
|
if (isJarAuthRequest(parsed)) {
|
|
958
1127
|
jar = await verifyJarRequest({ jarRequestParams: parsed, callbacks, wallet });
|
|
959
|
-
const parsedJarAuthRequestPayload = (0,
|
|
960
|
-
|
|
1128
|
+
const parsedJarAuthRequestPayload = (0, import_utils13.parseWithErrorHandling)(
|
|
1129
|
+
import_zod15.default.union([zOpenid4vpAuthorizationRequestDcApi, zOpenid4vpAuthorizationRequest]),
|
|
961
1130
|
jar.authRequestParams,
|
|
962
1131
|
"Invalid authorization request. Could not parse jar request payload as openid4vp auth request."
|
|
963
1132
|
);
|
|
@@ -977,13 +1146,22 @@ async function resolveOpenid4vpAuthorizationRequest(options) {
|
|
|
977
1146
|
omitOriginValidation
|
|
978
1147
|
});
|
|
979
1148
|
}
|
|
980
|
-
|
|
1149
|
+
let clientMetadata;
|
|
1150
|
+
if (!isOpenid4vpAuthorizationRequestDcApi(authRequestPayload) && authRequestPayload.client_metadata_uri) {
|
|
1151
|
+
clientMetadata = await fetchClientMetadata({ clientMetadataUri: authRequestPayload.client_metadata_uri });
|
|
1152
|
+
}
|
|
1153
|
+
const clientMeta = parseClientIdentifier({
|
|
1154
|
+
request: { ...authRequestPayload, client_metadata: clientMetadata ?? authRequestPayload.client_metadata },
|
|
1155
|
+
jar,
|
|
1156
|
+
callbacks,
|
|
1157
|
+
origin
|
|
1158
|
+
});
|
|
981
1159
|
let pex;
|
|
982
1160
|
let dcql;
|
|
983
1161
|
if (authRequestPayload.presentation_definition || authRequestPayload.presentation_definition_uri) {
|
|
984
1162
|
if (authRequestPayload.presentation_definition_uri) {
|
|
985
|
-
throw new
|
|
986
|
-
error:
|
|
1163
|
+
throw new import_oauth219.Oauth2ServerErrorResponseError({
|
|
1164
|
+
error: import_oauth219.Oauth2ErrorCodes.InvalidRequest,
|
|
987
1165
|
error_description: "Cannot fetch presentation definition from URI. Not supported."
|
|
988
1166
|
});
|
|
989
1167
|
}
|
|
@@ -998,7 +1176,7 @@ async function resolveOpenid4vpAuthorizationRequest(options) {
|
|
|
998
1176
|
const transactionData = authRequestPayload.transaction_data ? parseTransactionData({ transactionData: authRequestPayload.transaction_data }) : void 0;
|
|
999
1177
|
return {
|
|
1000
1178
|
transactionData,
|
|
1001
|
-
|
|
1179
|
+
requestPayload: authRequestPayload,
|
|
1002
1180
|
jar,
|
|
1003
1181
|
client: { ...clientMeta },
|
|
1004
1182
|
pex,
|
|
@@ -1021,8 +1199,8 @@ function validateOpenId4vpPayload(options) {
|
|
|
1021
1199
|
}
|
|
1022
1200
|
|
|
1023
1201
|
// src/authorization-response/create-authorization-response.ts
|
|
1024
|
-
var
|
|
1025
|
-
var
|
|
1202
|
+
var import_oauth222 = require("@openid4vc/oauth2");
|
|
1203
|
+
var import_utils14 = require("@openid4vc/utils");
|
|
1026
1204
|
|
|
1027
1205
|
// ../utils/src/date.ts
|
|
1028
1206
|
function addSecondsToDate(date, seconds) {
|
|
@@ -1030,7 +1208,7 @@ function addSecondsToDate(date, seconds) {
|
|
|
1030
1208
|
}
|
|
1031
1209
|
|
|
1032
1210
|
// src/jarm/jarm-auth-response-create.ts
|
|
1033
|
-
var
|
|
1211
|
+
var import_oauth220 = require("@openid4vc/oauth2");
|
|
1034
1212
|
async function createJarmAuthResponse(options) {
|
|
1035
1213
|
const { jarmAuthResponse, jweEncryptor, jwtSigner, callbacks } = options;
|
|
1036
1214
|
if (!jwtSigner && jweEncryptor) {
|
|
@@ -1039,16 +1217,16 @@ async function createJarmAuthResponse(options) {
|
|
|
1039
1217
|
}
|
|
1040
1218
|
if (jwtSigner && !jweEncryptor) {
|
|
1041
1219
|
const signed2 = await callbacks.signJwt(jwtSigner, {
|
|
1042
|
-
header: (0,
|
|
1220
|
+
header: (0, import_oauth220.jwtHeaderFromJwtSigner)(jwtSigner),
|
|
1043
1221
|
payload: jarmAuthResponse
|
|
1044
1222
|
});
|
|
1045
1223
|
return { jarmAuthResponseJwt: signed2.jwt };
|
|
1046
1224
|
}
|
|
1047
1225
|
if (!jwtSigner || !jweEncryptor) {
|
|
1048
|
-
throw new
|
|
1226
|
+
throw new import_oauth220.Oauth2Error("JWT signer and/or encryptor are required to create a JARM auth response.");
|
|
1049
1227
|
}
|
|
1050
1228
|
const signed = await callbacks.signJwt(jwtSigner, {
|
|
1051
|
-
header: (0,
|
|
1229
|
+
header: (0, import_oauth220.jwtHeaderFromJwtSigner)(jwtSigner),
|
|
1052
1230
|
payload: jarmAuthResponse
|
|
1053
1231
|
});
|
|
1054
1232
|
const encrypted = await callbacks.encryptJwe(jweEncryptor, signed.jwt);
|
|
@@ -1060,13 +1238,15 @@ function extractJwksFromClientMetadata(clientMetadata) {
|
|
|
1060
1238
|
const parsed = zJarmClientMetadataParsed.parse(clientMetadata);
|
|
1061
1239
|
const encryptionAlg = parsed.client_metadata.authorization_encrypted_response_enc;
|
|
1062
1240
|
const signingAlg = parsed.client_metadata.authorization_signed_response_alg;
|
|
1063
|
-
const encJwk = clientMetadata.jwks.keys.find((key) => key.use === "enc" && key.alg === encryptionAlg) ?? clientMetadata.jwks.keys.find((key) => key.use === "enc")
|
|
1064
|
-
|
|
1241
|
+
const encJwk = clientMetadata.jwks.keys.find((key) => key.use === "enc" && key.alg === encryptionAlg) ?? clientMetadata.jwks.keys.find((key) => key.use === "enc") ?? // fallback, take first key. HAIP does not specify requirement on enc
|
|
1242
|
+
clientMetadata.jwks.keys?.[0];
|
|
1243
|
+
const sigJwk = clientMetadata.jwks.keys.find((key) => key.use === "sig" && key.alg === signingAlg) ?? clientMetadata.jwks.keys.find((key) => key.use === "sig") ?? // falback, take first key
|
|
1244
|
+
clientMetadata.jwks.keys?.[0];
|
|
1065
1245
|
return { encJwk, sigJwk };
|
|
1066
1246
|
}
|
|
1067
1247
|
|
|
1068
1248
|
// src/jarm/jarm-response-mode.ts
|
|
1069
|
-
var
|
|
1249
|
+
var import_zod16 = require("zod");
|
|
1070
1250
|
var jarmResponseMode = [
|
|
1071
1251
|
"jwt",
|
|
1072
1252
|
"query.jwt",
|
|
@@ -1075,18 +1255,18 @@ var jarmResponseMode = [
|
|
|
1075
1255
|
"direct_post.jwt",
|
|
1076
1256
|
"dc_api.jwt"
|
|
1077
1257
|
];
|
|
1078
|
-
var zJarmResponseMode =
|
|
1258
|
+
var zJarmResponseMode = import_zod16.z.enum(jarmResponseMode);
|
|
1079
1259
|
var isJarmResponseMode = (responseMode) => {
|
|
1080
1260
|
return jarmResponseMode.includes(responseMode);
|
|
1081
1261
|
};
|
|
1082
1262
|
|
|
1083
1263
|
// src/jarm/metadata/jarm-assert-metadata-supported.ts
|
|
1084
|
-
var
|
|
1264
|
+
var import_oauth221 = require("@openid4vc/oauth2");
|
|
1085
1265
|
function assertValueSupported(options) {
|
|
1086
1266
|
const { errorMessage, supported, actual } = options;
|
|
1087
1267
|
const intersection = supported.find((value) => value === actual);
|
|
1088
1268
|
if (!intersection) {
|
|
1089
|
-
throw new
|
|
1269
|
+
throw new import_oauth221.Oauth2Error(errorMessage);
|
|
1090
1270
|
}
|
|
1091
1271
|
return intersection;
|
|
1092
1272
|
}
|
|
@@ -1121,77 +1301,77 @@ function jarmAssertMetadataSupported(options) {
|
|
|
1121
1301
|
|
|
1122
1302
|
// src/authorization-response/create-authorization-response.ts
|
|
1123
1303
|
async function createOpenid4vpAuthorizationResponse(options) {
|
|
1124
|
-
const {
|
|
1125
|
-
const
|
|
1126
|
-
...
|
|
1127
|
-
..."state" in
|
|
1304
|
+
const { requestPayload, jarm, callbacks } = options;
|
|
1305
|
+
const responsePayload = {
|
|
1306
|
+
...options.responsePayload,
|
|
1307
|
+
..."state" in requestPayload && { state: requestPayload.state }
|
|
1128
1308
|
};
|
|
1129
|
-
if (
|
|
1130
|
-
throw new
|
|
1131
|
-
`Missing jarm options for creating Jarm response with response mode '${
|
|
1309
|
+
if (requestPayload.response_mode && isJarmResponseMode(requestPayload.response_mode) && !jarm) {
|
|
1310
|
+
throw new import_oauth222.Oauth2Error(
|
|
1311
|
+
`Missing jarm options for creating Jarm response with response mode '${requestPayload.response_mode}'`
|
|
1132
1312
|
);
|
|
1133
1313
|
}
|
|
1134
1314
|
if (!jarm) {
|
|
1135
1315
|
return {
|
|
1136
|
-
|
|
1316
|
+
responsePayload
|
|
1137
1317
|
};
|
|
1138
1318
|
}
|
|
1139
|
-
if (!
|
|
1140
|
-
throw new
|
|
1319
|
+
if (!requestPayload.client_metadata) {
|
|
1320
|
+
throw new import_oauth222.Oauth2Error("Missing client metadata in the request params to assert Jarm metadata support.");
|
|
1141
1321
|
}
|
|
1142
|
-
if (!
|
|
1143
|
-
throw new
|
|
1144
|
-
error:
|
|
1322
|
+
if (!requestPayload.client_metadata.jwks) {
|
|
1323
|
+
throw new import_oauth222.Oauth2ServerErrorResponseError({
|
|
1324
|
+
error: import_oauth222.Oauth2ErrorCodes.InvalidRequest,
|
|
1145
1325
|
error_description: "Missing JWKS in client metadata. Cannot extract encryption JWK."
|
|
1146
1326
|
});
|
|
1147
1327
|
}
|
|
1148
1328
|
const supportedJarmMetadata = jarmAssertMetadataSupported({
|
|
1149
|
-
clientMetadata:
|
|
1329
|
+
clientMetadata: requestPayload.client_metadata,
|
|
1150
1330
|
serverMetadata: jarm.serverMetadata
|
|
1151
1331
|
});
|
|
1152
1332
|
const clientMetaJwks = extractJwksFromClientMetadata({
|
|
1153
|
-
...
|
|
1154
|
-
jwks:
|
|
1333
|
+
...requestPayload.client_metadata,
|
|
1334
|
+
jwks: requestPayload.client_metadata.jwks
|
|
1155
1335
|
});
|
|
1156
1336
|
if (!clientMetaJwks?.encJwk) {
|
|
1157
|
-
throw new
|
|
1158
|
-
error:
|
|
1337
|
+
throw new import_oauth222.Oauth2ServerErrorResponseError({
|
|
1338
|
+
error: import_oauth222.Oauth2ErrorCodes.InvalidRequest,
|
|
1159
1339
|
error_description: "Could not extract encryption JWK from client metadata. Failed to create JARM response."
|
|
1160
1340
|
});
|
|
1161
1341
|
}
|
|
1162
1342
|
let additionalJwtPayload;
|
|
1163
1343
|
if (jarm?.jwtSigner) {
|
|
1164
1344
|
if (!jarm.authorizationServer) {
|
|
1165
|
-
throw new
|
|
1166
|
-
error:
|
|
1345
|
+
throw new import_oauth222.Oauth2ServerErrorResponseError({
|
|
1346
|
+
error: import_oauth222.Oauth2ErrorCodes.InvalidRequest,
|
|
1167
1347
|
error_description: "Missing required iss in JARM configuration for creating OpenID4VP authorization response."
|
|
1168
1348
|
});
|
|
1169
1349
|
}
|
|
1170
1350
|
if (!jarm.audience) {
|
|
1171
|
-
throw new
|
|
1172
|
-
error:
|
|
1351
|
+
throw new import_oauth222.Oauth2ServerErrorResponseError({
|
|
1352
|
+
error: import_oauth222.Oauth2ErrorCodes.InvalidRequest,
|
|
1173
1353
|
error_description: "Missing required aud in JARM configuration for creating OpenID4VP authorization response."
|
|
1174
1354
|
});
|
|
1175
1355
|
}
|
|
1176
1356
|
additionalJwtPayload = {
|
|
1177
1357
|
iss: jarm.authorizationServer,
|
|
1178
1358
|
aud: jarm.audience,
|
|
1179
|
-
exp: jarm.expiresInSeconds ?? (0,
|
|
1359
|
+
exp: jarm.expiresInSeconds ?? (0, import_utils14.dateToSeconds)(addSecondsToDate(/* @__PURE__ */ new Date(), 60 * 10))
|
|
1180
1360
|
// default: 10 minutes
|
|
1181
1361
|
};
|
|
1182
1362
|
}
|
|
1183
|
-
const
|
|
1184
|
-
...
|
|
1363
|
+
const jarmResponsePayload = {
|
|
1364
|
+
...responsePayload,
|
|
1185
1365
|
...additionalJwtPayload
|
|
1186
1366
|
};
|
|
1187
1367
|
const result = await createJarmAuthResponse({
|
|
1188
|
-
jarmAuthResponse:
|
|
1368
|
+
jarmAuthResponse: jarmResponsePayload,
|
|
1189
1369
|
jwtSigner: jarm?.jwtSigner,
|
|
1190
1370
|
jweEncryptor: jarm?.encryption && (supportedJarmMetadata.type === "encrypt" || supportedJarmMetadata.type === "sign_encrypt") ? {
|
|
1191
1371
|
method: "jwk",
|
|
1192
1372
|
publicJwk: clientMetaJwks.encJwk,
|
|
1193
1373
|
apu: jarm.encryption?.nonce,
|
|
1194
|
-
apv:
|
|
1374
|
+
apv: requestPayload.nonce,
|
|
1195
1375
|
alg: supportedJarmMetadata.client_metadata.authorization_encrypted_response_alg,
|
|
1196
1376
|
enc: supportedJarmMetadata.client_metadata.authorization_encrypted_response_enc
|
|
1197
1377
|
} : void 0,
|
|
@@ -1201,32 +1381,32 @@ async function createOpenid4vpAuthorizationResponse(options) {
|
|
|
1201
1381
|
}
|
|
1202
1382
|
});
|
|
1203
1383
|
return {
|
|
1204
|
-
|
|
1384
|
+
responsePayload: jarmResponsePayload,
|
|
1205
1385
|
jarm: { responseJwt: result.jarmAuthResponseJwt }
|
|
1206
1386
|
};
|
|
1207
1387
|
}
|
|
1208
1388
|
|
|
1209
1389
|
// src/authorization-response/submit-authorization-response.ts
|
|
1210
|
-
var
|
|
1211
|
-
var import_utils15 = require("@openid4vc/utils");
|
|
1390
|
+
var import_oauth224 = require("@openid4vc/oauth2");
|
|
1212
1391
|
var import_utils16 = require("@openid4vc/utils");
|
|
1392
|
+
var import_utils17 = require("@openid4vc/utils");
|
|
1213
1393
|
|
|
1214
1394
|
// src/jarm/jarm-auth-response-send.ts
|
|
1215
|
-
var
|
|
1216
|
-
var
|
|
1395
|
+
var import_oauth223 = require("@openid4vc/oauth2");
|
|
1396
|
+
var import_utils15 = require("@openid4vc/utils");
|
|
1217
1397
|
var jarmAuthResponseSend = (options) => {
|
|
1218
1398
|
const { authRequest, jarmAuthResponseJwt, callbacks } = options;
|
|
1219
1399
|
const responseEndpoint = authRequest.response_uri ?? authRequest.redirect_uri;
|
|
1220
1400
|
if (!responseEndpoint) {
|
|
1221
|
-
throw new
|
|
1401
|
+
throw new import_oauth223.Oauth2Error(`Either 'response_uri' or 'redirect_uri' MUST be present in the authorization request`);
|
|
1222
1402
|
}
|
|
1223
|
-
const responseEndpointUrl = new
|
|
1403
|
+
const responseEndpointUrl = new import_utils15.URL(responseEndpoint);
|
|
1224
1404
|
return handleDirectPostJwt(responseEndpointUrl, jarmAuthResponseJwt, callbacks);
|
|
1225
1405
|
};
|
|
1226
1406
|
async function handleDirectPostJwt(responseEndpoint, responseJwt, callbacks) {
|
|
1227
|
-
const response = await (callbacks.fetch ??
|
|
1407
|
+
const response = await (callbacks.fetch ?? import_utils15.defaultFetcher)(responseEndpoint, {
|
|
1228
1408
|
method: "POST",
|
|
1229
|
-
headers: { "Content-Type":
|
|
1409
|
+
headers: { "Content-Type": import_utils15.ContentType.XWwwFormUrlencoded },
|
|
1230
1410
|
body: `response=${responseJwt}`
|
|
1231
1411
|
});
|
|
1232
1412
|
return {
|
|
@@ -1237,27 +1417,27 @@ async function handleDirectPostJwt(responseEndpoint, responseJwt, callbacks) {
|
|
|
1237
1417
|
|
|
1238
1418
|
// src/authorization-response/submit-authorization-response.ts
|
|
1239
1419
|
async function submitOpenid4vpAuthorizationResponse(options) {
|
|
1240
|
-
const {
|
|
1241
|
-
const url =
|
|
1420
|
+
const { requestPayload, responsePayload, jarm, callbacks } = options;
|
|
1421
|
+
const url = requestPayload.response_uri;
|
|
1242
1422
|
if (jarm) {
|
|
1243
1423
|
return jarmAuthResponseSend({
|
|
1244
|
-
authRequest:
|
|
1424
|
+
authRequest: requestPayload,
|
|
1245
1425
|
jarmAuthResponseJwt: jarm.responseJwt,
|
|
1246
1426
|
callbacks
|
|
1247
1427
|
});
|
|
1248
1428
|
}
|
|
1249
1429
|
if (!url) {
|
|
1250
|
-
throw new
|
|
1430
|
+
throw new import_oauth224.Oauth2Error(
|
|
1251
1431
|
"Failed to submit OpenId4Vp Authorization Response. No redirect_uri or response_uri provided."
|
|
1252
1432
|
);
|
|
1253
1433
|
}
|
|
1254
|
-
const fetch = callbacks.fetch ??
|
|
1255
|
-
const encodedResponse = (0,
|
|
1434
|
+
const fetch = callbacks.fetch ?? import_utils16.defaultFetcher;
|
|
1435
|
+
const encodedResponse = (0, import_utils17.objectToQueryParams)(responsePayload);
|
|
1256
1436
|
const submissionResponse = await fetch(url, {
|
|
1257
1437
|
method: "POST",
|
|
1258
1438
|
body: encodedResponse,
|
|
1259
1439
|
headers: {
|
|
1260
|
-
"Content-Type":
|
|
1440
|
+
"Content-Type": import_utils16.ContentType.XWwwFormUrlencoded
|
|
1261
1441
|
}
|
|
1262
1442
|
});
|
|
1263
1443
|
return {
|
|
@@ -1267,33 +1447,33 @@ async function submitOpenid4vpAuthorizationResponse(options) {
|
|
|
1267
1447
|
}
|
|
1268
1448
|
|
|
1269
1449
|
// src/authorization-response/validate-authorization-response.ts
|
|
1270
|
-
var
|
|
1450
|
+
var import_oauth227 = require("@openid4vc/oauth2");
|
|
1271
1451
|
|
|
1272
1452
|
// src/vp-token/parse-presentations-from-vp-token.ts
|
|
1273
|
-
var
|
|
1274
|
-
var
|
|
1275
|
-
var
|
|
1276
|
-
var
|
|
1453
|
+
var import_oauth225 = require("@openid4vc/oauth2");
|
|
1454
|
+
var import_oauth226 = require("@openid4vc/oauth2");
|
|
1455
|
+
var import_utils18 = require("@openid4vc/utils");
|
|
1456
|
+
var import_zod17 = require("zod");
|
|
1277
1457
|
function parsePresentationsFromVpToken(options) {
|
|
1278
1458
|
const { vpToken: _vpToken } = options;
|
|
1279
|
-
const vpToken = (0,
|
|
1459
|
+
const vpToken = (0, import_utils18.parseIfJson)(_vpToken);
|
|
1280
1460
|
if (Array.isArray(vpToken)) {
|
|
1281
1461
|
if (vpToken.length === 0) {
|
|
1282
|
-
throw new
|
|
1462
|
+
throw new import_oauth225.Oauth2Error("Could not parse vp_token. vp_token is an empty array.");
|
|
1283
1463
|
}
|
|
1284
1464
|
return vpToken.map((token, idx) => parseSinglePresentationFromVpToken({ vpToken: token, path: `$[${idx}]` }));
|
|
1285
1465
|
}
|
|
1286
1466
|
if (typeof vpToken === "string" || typeof vpToken === "object") {
|
|
1287
1467
|
return [parseSinglePresentationFromVpToken({ vpToken, path: "$" })];
|
|
1288
1468
|
}
|
|
1289
|
-
throw new
|
|
1469
|
+
throw new import_oauth225.Oauth2Error(
|
|
1290
1470
|
`Could not parse vp_token. Expected a string or an array of strings. Received: ${typeof vpToken}`
|
|
1291
1471
|
);
|
|
1292
1472
|
}
|
|
1293
1473
|
function parseDcqlPresentationFromVpToken(options) {
|
|
1294
1474
|
const { vpToken: _vpToken } = options;
|
|
1295
|
-
const vpToken = (0,
|
|
1296
|
-
const parsed = (0,
|
|
1475
|
+
const vpToken = (0, import_utils18.parseIfJson)(_vpToken);
|
|
1476
|
+
const parsed = (0, import_utils18.parseWithErrorHandling)(import_zod17.z.object({}).passthrough(), vpToken);
|
|
1297
1477
|
const dcqlPresentationRecord = Object.fromEntries(
|
|
1298
1478
|
Object.entries(parsed).map(([key, value]) => {
|
|
1299
1479
|
return [key, parseSinglePresentationFromVpToken({ vpToken: value })];
|
|
@@ -1303,25 +1483,25 @@ function parseDcqlPresentationFromVpToken(options) {
|
|
|
1303
1483
|
}
|
|
1304
1484
|
function parseSinglePresentationFromVpToken(options) {
|
|
1305
1485
|
const { vpToken: _vpToken, path } = options;
|
|
1306
|
-
const vpToken = (0,
|
|
1307
|
-
const zLdpVpProof =
|
|
1308
|
-
const ldpVpParseResult =
|
|
1309
|
-
"@context":
|
|
1310
|
-
verifiableCredential:
|
|
1311
|
-
proof:
|
|
1486
|
+
const vpToken = (0, import_utils18.parseIfJson)(_vpToken);
|
|
1487
|
+
const zLdpVpProof = import_zod17.z.object({ challenge: import_zod17.z.string().optional() }).passthrough();
|
|
1488
|
+
const ldpVpParseResult = import_zod17.z.object({
|
|
1489
|
+
"@context": import_zod17.z.string().optional(),
|
|
1490
|
+
verifiableCredential: import_zod17.z.string().optional(),
|
|
1491
|
+
proof: import_zod17.z.union([zLdpVpProof, import_zod17.z.array(zLdpVpProof)]).optional()
|
|
1312
1492
|
}).passthrough().safeParse(vpToken);
|
|
1313
1493
|
if (ldpVpParseResult.success && (ldpVpParseResult.data["@context"] || ldpVpParseResult.data.verifiableCredential)) {
|
|
1314
1494
|
const challenge = Array.isArray(ldpVpParseResult.data.proof) ? ldpVpParseResult.data.proof.map((proof) => proof.challenge) : ldpVpParseResult.data.proof?.challenge;
|
|
1315
1495
|
if (Array.isArray(challenge)) {
|
|
1316
1496
|
const allNoncesAreTheSame = challenge.every((nonce) => nonce === challenge[0]);
|
|
1317
1497
|
if (!allNoncesAreTheSame) {
|
|
1318
|
-
throw new
|
|
1498
|
+
throw new import_oauth225.Oauth2Error(
|
|
1319
1499
|
"Failed to parse presentation from vp_token. LDP presentation is missing the proof.challenge parameter."
|
|
1320
1500
|
);
|
|
1321
1501
|
}
|
|
1322
1502
|
}
|
|
1323
1503
|
if (!challenge) {
|
|
1324
|
-
throw new
|
|
1504
|
+
throw new import_oauth225.Oauth2Error(
|
|
1325
1505
|
"Failed to parse presentation from vp_token. LDP presentation is missing the proof.challenge parameter."
|
|
1326
1506
|
);
|
|
1327
1507
|
}
|
|
@@ -1332,7 +1512,7 @@ function parseSinglePresentationFromVpToken(options) {
|
|
|
1332
1512
|
nonce: Array.isArray(challenge) ? challenge[0] : challenge
|
|
1333
1513
|
};
|
|
1334
1514
|
}
|
|
1335
|
-
if ((0,
|
|
1515
|
+
if ((0, import_utils18.isObject)(vpToken) && (vpToken.schema_id || vpToken.cred_def_id)) {
|
|
1336
1516
|
return {
|
|
1337
1517
|
format: "ac_vp",
|
|
1338
1518
|
presentation: vpToken,
|
|
@@ -1340,7 +1520,7 @@ function parseSinglePresentationFromVpToken(options) {
|
|
|
1340
1520
|
};
|
|
1341
1521
|
}
|
|
1342
1522
|
if (typeof vpToken !== "string") {
|
|
1343
|
-
throw new
|
|
1523
|
+
throw new import_oauth225.Oauth2Error(
|
|
1344
1524
|
`Could not parse vp_token. Expected a string since the vp_token is neither a ldp_vp nor an ac_vp. Received: ${typeof vpToken}`
|
|
1345
1525
|
);
|
|
1346
1526
|
}
|
|
@@ -1349,7 +1529,7 @@ function parseSinglePresentationFromVpToken(options) {
|
|
|
1349
1529
|
const keyBindingJwt = split[split.length - 1];
|
|
1350
1530
|
let nonce;
|
|
1351
1531
|
try {
|
|
1352
|
-
const decoded = (0,
|
|
1532
|
+
const decoded = (0, import_oauth225.decodeJwt)({ jwt: keyBindingJwt });
|
|
1353
1533
|
nonce = decoded.payload.nonce;
|
|
1354
1534
|
} catch (error) {
|
|
1355
1535
|
nonce = void 0;
|
|
@@ -1360,11 +1540,11 @@ function parseSinglePresentationFromVpToken(options) {
|
|
|
1360
1540
|
path: options.path
|
|
1361
1541
|
};
|
|
1362
1542
|
}
|
|
1363
|
-
const result =
|
|
1543
|
+
const result = import_oauth226.zCompactJwt.safeParse(vpToken);
|
|
1364
1544
|
if (result.success) {
|
|
1365
1545
|
let nonce;
|
|
1366
1546
|
try {
|
|
1367
|
-
const decoded = (0,
|
|
1547
|
+
const decoded = (0, import_oauth225.decodeJwt)({ jwt: vpToken });
|
|
1368
1548
|
nonce = decoded.payload.nonce;
|
|
1369
1549
|
} catch (error) {
|
|
1370
1550
|
nonce = void 0;
|
|
@@ -1385,98 +1565,98 @@ function parseSinglePresentationFromVpToken(options) {
|
|
|
1385
1565
|
|
|
1386
1566
|
// src/authorization-response/validate-authorization-response.ts
|
|
1387
1567
|
function validateOpenid4vpAuthorizationResponse(options) {
|
|
1388
|
-
const {
|
|
1389
|
-
if (!
|
|
1390
|
-
throw new
|
|
1568
|
+
const { requestPayload, responsePayload } = options;
|
|
1569
|
+
if (!responsePayload.vp_token) {
|
|
1570
|
+
throw new import_oauth227.Oauth2Error("Failed to verify OpenId4Vp Authorization Response. vp_token is missing.");
|
|
1391
1571
|
}
|
|
1392
|
-
if ("state" in
|
|
1393
|
-
throw new
|
|
1572
|
+
if ("state" in requestPayload && requestPayload.state !== responsePayload.state) {
|
|
1573
|
+
throw new import_oauth227.Oauth2Error("OpenId4Vp Authorization Response state mismatch.");
|
|
1394
1574
|
}
|
|
1395
|
-
if (
|
|
1396
|
-
throw new
|
|
1575
|
+
if (responsePayload.id_token) {
|
|
1576
|
+
throw new import_oauth227.Oauth2Error("OpenId4Vp Authorization Response id_token is not supported.");
|
|
1397
1577
|
}
|
|
1398
|
-
if (
|
|
1399
|
-
if (!
|
|
1400
|
-
throw new
|
|
1578
|
+
if (responsePayload.presentation_submission) {
|
|
1579
|
+
if (!requestPayload.presentation_definition) {
|
|
1580
|
+
throw new import_oauth227.Oauth2Error("OpenId4Vp Authorization Request is missing the required presentation_definition.");
|
|
1401
1581
|
}
|
|
1402
|
-
const presentations = parsePresentationsFromVpToken({ vpToken:
|
|
1403
|
-
if (presentations.every((p) => p.nonce) && !presentations.every((p) => p.nonce ===
|
|
1404
|
-
throw new
|
|
1582
|
+
const presentations = parsePresentationsFromVpToken({ vpToken: responsePayload.vp_token });
|
|
1583
|
+
if (presentations.every((p) => p.nonce) && !presentations.every((p) => p.nonce === requestPayload.nonce)) {
|
|
1584
|
+
throw new import_oauth227.Oauth2Error(
|
|
1405
1585
|
"Presentation nonce mismatch. The nonce of some presentations does not match the nonce of the request."
|
|
1406
1586
|
);
|
|
1407
1587
|
}
|
|
1408
1588
|
return {
|
|
1409
1589
|
type: "pex",
|
|
1410
|
-
pex: "scope" in
|
|
1411
|
-
scope:
|
|
1412
|
-
presentationSubmission:
|
|
1590
|
+
pex: "scope" in requestPayload && requestPayload.scope ? {
|
|
1591
|
+
scope: requestPayload.scope,
|
|
1592
|
+
presentationSubmission: responsePayload.presentation_submission,
|
|
1413
1593
|
presentations
|
|
1414
1594
|
} : {
|
|
1415
|
-
presentationDefinition:
|
|
1416
|
-
presentationSubmission:
|
|
1595
|
+
presentationDefinition: requestPayload.presentation_definition,
|
|
1596
|
+
presentationSubmission: responsePayload.presentation_submission,
|
|
1417
1597
|
presentations
|
|
1418
1598
|
}
|
|
1419
1599
|
};
|
|
1420
1600
|
}
|
|
1421
|
-
if (
|
|
1422
|
-
if (Array.isArray(
|
|
1423
|
-
throw new
|
|
1601
|
+
if (requestPayload.dcql_query) {
|
|
1602
|
+
if (Array.isArray(responsePayload.vp_token)) {
|
|
1603
|
+
throw new import_oauth227.Oauth2Error(
|
|
1424
1604
|
"The OpenId4Vp Authorization Response contains multiple vp_token values. In combination with dcql this is not possible."
|
|
1425
1605
|
);
|
|
1426
1606
|
}
|
|
1427
|
-
if (typeof
|
|
1428
|
-
throw new
|
|
1607
|
+
if (typeof responsePayload.vp_token !== "string" && typeof responsePayload.vp_token !== "object") {
|
|
1608
|
+
throw new import_oauth227.Oauth2Error("With DCQL the vp_token must be a JSON-encoded object.");
|
|
1429
1609
|
}
|
|
1430
|
-
const presentation = parseDcqlPresentationFromVpToken({ vpToken:
|
|
1431
|
-
if (Object.values(presentation).every((p) => p.nonce) && !Object.values(presentation).every((p) => p.nonce ===
|
|
1432
|
-
throw new
|
|
1610
|
+
const presentation = parseDcqlPresentationFromVpToken({ vpToken: responsePayload.vp_token });
|
|
1611
|
+
if (Object.values(presentation).every((p) => p.nonce) && !Object.values(presentation).every((p) => p.nonce === requestPayload.nonce)) {
|
|
1612
|
+
throw new import_oauth227.Oauth2Error(
|
|
1433
1613
|
"Presentation nonce mismatch. The nonce of some presentations does not match the nonce of the request."
|
|
1434
1614
|
);
|
|
1435
1615
|
}
|
|
1436
1616
|
return {
|
|
1437
1617
|
type: "dcql",
|
|
1438
|
-
dcql: "scope" in
|
|
1439
|
-
scope:
|
|
1618
|
+
dcql: "scope" in requestPayload && requestPayload.scope ? {
|
|
1619
|
+
scope: requestPayload.scope,
|
|
1440
1620
|
presentation
|
|
1441
1621
|
} : {
|
|
1442
|
-
query:
|
|
1622
|
+
query: requestPayload.dcql_query,
|
|
1443
1623
|
presentation
|
|
1444
1624
|
}
|
|
1445
1625
|
};
|
|
1446
1626
|
}
|
|
1447
|
-
throw new
|
|
1627
|
+
throw new import_oauth227.Oauth2Error(
|
|
1448
1628
|
"Invalid OpenId4Vp Authorization Response. Response neither contains a presentation_submission nor a dcql_query."
|
|
1449
1629
|
);
|
|
1450
1630
|
}
|
|
1451
1631
|
|
|
1452
1632
|
// src/authorization-response/parse-authorization-response.ts
|
|
1453
|
-
var
|
|
1633
|
+
var import_oauth229 = require("@openid4vc/oauth2");
|
|
1454
1634
|
|
|
1455
1635
|
// src/authorization-response/parse-authorization-response-payload.ts
|
|
1456
|
-
var
|
|
1636
|
+
var import_utils19 = require("@openid4vc/utils");
|
|
1457
1637
|
|
|
1458
1638
|
// src/authorization-response/z-authorization-response.ts
|
|
1459
|
-
var
|
|
1639
|
+
var import_zod19 = require("zod");
|
|
1460
1640
|
|
|
1461
1641
|
// src/vp-token/z-vp-token.ts
|
|
1462
|
-
var
|
|
1463
|
-
var zVpToken =
|
|
1642
|
+
var import_zod18 = require("zod");
|
|
1643
|
+
var zVpToken = import_zod18.z.union([import_zod18.z.string(), import_zod18.z.array(import_zod18.z.union([import_zod18.z.string(), import_zod18.z.record(import_zod18.z.any())])), import_zod18.z.record(import_zod18.z.any())]);
|
|
1464
1644
|
|
|
1465
1645
|
// src/authorization-response/z-authorization-response.ts
|
|
1466
|
-
var zOpenid4vpAuthorizationResponse =
|
|
1467
|
-
state:
|
|
1468
|
-
id_token:
|
|
1646
|
+
var zOpenid4vpAuthorizationResponse = import_zod19.z.object({
|
|
1647
|
+
state: import_zod19.z.string().optional(),
|
|
1648
|
+
id_token: import_zod19.z.string().optional(),
|
|
1469
1649
|
vp_token: zVpToken,
|
|
1470
|
-
presentation_submission:
|
|
1471
|
-
refresh_token:
|
|
1472
|
-
token_type:
|
|
1473
|
-
access_token:
|
|
1474
|
-
expires_in:
|
|
1650
|
+
presentation_submission: import_zod19.z.unknown().optional(),
|
|
1651
|
+
refresh_token: import_zod19.z.string().optional(),
|
|
1652
|
+
token_type: import_zod19.z.string().optional(),
|
|
1653
|
+
access_token: import_zod19.z.string().optional(),
|
|
1654
|
+
expires_in: import_zod19.z.number().optional()
|
|
1475
1655
|
}).passthrough();
|
|
1476
1656
|
|
|
1477
1657
|
// src/authorization-response/parse-authorization-response-payload.ts
|
|
1478
1658
|
function parseOpenid4VpAuthorizationResponsePayload(payload) {
|
|
1479
|
-
return (0,
|
|
1659
|
+
return (0, import_utils19.parseWithErrorHandling)(
|
|
1480
1660
|
zOpenid4vpAuthorizationResponse,
|
|
1481
1661
|
payload,
|
|
1482
1662
|
"Failed to parse openid4vp authorization response."
|
|
@@ -1484,19 +1664,19 @@ function parseOpenid4VpAuthorizationResponsePayload(payload) {
|
|
|
1484
1664
|
}
|
|
1485
1665
|
|
|
1486
1666
|
// src/authorization-response/parse-jarm-authorization-response.ts
|
|
1487
|
-
var
|
|
1488
|
-
var
|
|
1489
|
-
var
|
|
1667
|
+
var import_oauth228 = require("@openid4vc/oauth2");
|
|
1668
|
+
var import_utils20 = require("@openid4vc/utils");
|
|
1669
|
+
var import_zod20 = __toESM(require("zod"));
|
|
1490
1670
|
async function parseJarmAuthorizationResponse(options) {
|
|
1491
1671
|
const { jarmResponseJwt, callbacks } = options;
|
|
1492
|
-
const jarmAuthorizationResponseJwt = (0,
|
|
1493
|
-
|
|
1672
|
+
const jarmAuthorizationResponseJwt = (0, import_utils20.parseWithErrorHandling)(
|
|
1673
|
+
import_zod20.default.union([import_oauth228.zCompactJwt, import_oauth228.zCompactJwe]),
|
|
1494
1674
|
jarmResponseJwt,
|
|
1495
1675
|
"Invalid jarm authorization response jwt."
|
|
1496
1676
|
);
|
|
1497
1677
|
const verifiedJarmResponse = await verifyJarmAuthorizationResponse({ jarmAuthorizationResponseJwt, callbacks });
|
|
1498
|
-
const zJarmHeader =
|
|
1499
|
-
const { header: jarmHeader } = (0,
|
|
1678
|
+
const zJarmHeader = import_zod20.default.object({ ...import_oauth228.zJwtHeader.shape, apu: import_zod20.default.string().optional(), apv: import_zod20.default.string().optional() });
|
|
1679
|
+
const { header: jarmHeader } = (0, import_oauth228.decodeJwtHeader)({
|
|
1500
1680
|
jwt: jarmAuthorizationResponseJwt,
|
|
1501
1681
|
headerSchema: zJarmHeader
|
|
1502
1682
|
});
|
|
@@ -1504,27 +1684,27 @@ async function parseJarmAuthorizationResponse(options) {
|
|
|
1504
1684
|
authorizationRequest: verifiedJarmResponse.authorizationRequest
|
|
1505
1685
|
});
|
|
1506
1686
|
if (parsedAuthorizationRequest.type !== "openid4vp" && parsedAuthorizationRequest.type !== "openid4vp_dc_api") {
|
|
1507
|
-
throw new
|
|
1687
|
+
throw new import_oauth228.Oauth2Error("Invalid authorization request. Could not parse openid4vp authorization request.");
|
|
1508
1688
|
}
|
|
1509
1689
|
const authResponsePayload = parseOpenid4VpAuthorizationResponsePayload(verifiedJarmResponse.jarmAuthResponse);
|
|
1510
1690
|
const validateOpenId4vpResponse = validateOpenid4vpAuthorizationResponse({
|
|
1511
|
-
|
|
1512
|
-
|
|
1691
|
+
requestPayload: parsedAuthorizationRequest.params,
|
|
1692
|
+
responsePayload: authResponsePayload
|
|
1513
1693
|
});
|
|
1514
1694
|
const authRequestPayload = parsedAuthorizationRequest.params;
|
|
1515
1695
|
if (!authRequestPayload.response_mode || !isJarmResponseMode(authRequestPayload.response_mode)) {
|
|
1516
|
-
throw new
|
|
1696
|
+
throw new import_oauth228.Oauth2Error(
|
|
1517
1697
|
`Invalid response mode for jarm response. Response mode: '${authRequestPayload.response_mode ?? "fragment"}'`
|
|
1518
1698
|
);
|
|
1519
1699
|
}
|
|
1520
1700
|
let mdocGeneratedNonce = void 0;
|
|
1521
1701
|
if (jarmHeader?.apu) {
|
|
1522
|
-
mdocGeneratedNonce = (0,
|
|
1702
|
+
mdocGeneratedNonce = (0, import_utils20.encodeToUtf8String)((0, import_utils20.decodeBase64)(jarmHeader.apu));
|
|
1523
1703
|
}
|
|
1524
1704
|
if (jarmHeader?.apv) {
|
|
1525
|
-
const jarmRequestNonce = (0,
|
|
1705
|
+
const jarmRequestNonce = (0, import_utils20.encodeToUtf8String)((0, import_utils20.decodeBase64)(jarmHeader.apv));
|
|
1526
1706
|
if (jarmRequestNonce !== authRequestPayload.nonce) {
|
|
1527
|
-
throw new
|
|
1707
|
+
throw new import_oauth228.Oauth2Error("The nonce in the jarm header does not match the nonce in the request.");
|
|
1528
1708
|
}
|
|
1529
1709
|
}
|
|
1530
1710
|
return {
|
|
@@ -1545,15 +1725,15 @@ async function parseOpenid4vpAuthorizationResponse(options) {
|
|
|
1545
1725
|
const { authorizationRequest } = await callbacks.getOpenid4vpAuthorizationRequest(authResponsePayload);
|
|
1546
1726
|
const parsedAuthRequest = parseOpenid4vpAuthorizationRequestPayload({ authorizationRequest });
|
|
1547
1727
|
if (parsedAuthRequest.type !== "openid4vp" && parsedAuthRequest.type !== "openid4vp_dc_api") {
|
|
1548
|
-
throw new
|
|
1728
|
+
throw new import_oauth229.Oauth2Error("Invalid authorization request. Could not parse openid4vp authorization request.");
|
|
1549
1729
|
}
|
|
1550
1730
|
const authRequestPayload = parsedAuthRequest.params;
|
|
1551
1731
|
const validateOpenId4vpResponse = validateOpenid4vpAuthorizationResponse({
|
|
1552
|
-
|
|
1553
|
-
|
|
1732
|
+
requestPayload: authRequestPayload,
|
|
1733
|
+
responsePayload: authResponsePayload
|
|
1554
1734
|
});
|
|
1555
1735
|
if (authRequestPayload.response_mode && isJarmResponseMode(authRequestPayload.response_mode)) {
|
|
1556
|
-
throw new
|
|
1736
|
+
throw new import_oauth229.Oauth2ServerErrorResponseError(
|
|
1557
1737
|
{
|
|
1558
1738
|
error: "invalid_request",
|
|
1559
1739
|
error_description: "Invalid response mode for openid4vp response. Expected jarm response."
|
|
@@ -1616,23 +1796,12 @@ var Openid4vpVerifier = class {
|
|
|
1616
1796
|
};
|
|
1617
1797
|
|
|
1618
1798
|
// src/models/z-credential-formats.ts
|
|
1619
|
-
var import_zod20 = require("zod");
|
|
1620
|
-
var zCredentialFormat = import_zod20.z.enum(["jwt_vc_json", "ldp_vc", "ac_vc", "mso_mdoc", "dc+sd-jwt"]);
|
|
1621
|
-
|
|
1622
|
-
// src/models/z-proof-formats.ts
|
|
1623
1799
|
var import_zod21 = require("zod");
|
|
1624
|
-
var
|
|
1800
|
+
var zCredentialFormat = import_zod21.z.enum(["jwt_vc_json", "ldp_vc", "ac_vc", "mso_mdoc", "dc+sd-jwt", "vc+sd-jwt"]);
|
|
1625
1801
|
|
|
1626
|
-
// src/models/z-
|
|
1802
|
+
// src/models/z-proof-formats.ts
|
|
1627
1803
|
var import_zod22 = require("zod");
|
|
1628
|
-
var
|
|
1629
|
-
presentation_definition_uri_supported: import_zod22.z.optional(import_zod22.z.boolean()),
|
|
1630
|
-
vp_formats_supported: zVpFormatsSupported,
|
|
1631
|
-
client_id_schemes_supported: import_zod22.z.optional(import_zod22.z.array(zClientIdScheme)),
|
|
1632
|
-
request_object_signing_alg_values_supported: import_zod22.z.optional(import_zod22.z.array(import_zod22.z.string())),
|
|
1633
|
-
authorization_encryption_alg_values_supported: import_zod22.z.optional(import_zod22.z.array(import_zod22.z.string())),
|
|
1634
|
-
authorization_encryption_enc_values_supported: import_zod22.z.optional(import_zod22.z.array(import_zod22.z.string()))
|
|
1635
|
-
});
|
|
1804
|
+
var zProofFormat = import_zod22.z.enum(["jwt_vp_json", "ldc_vp", "ac_vp", "dc+sd-jwt", "vc+sd-jwt", "mso_mdoc"]);
|
|
1636
1805
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1637
1806
|
0 && (module.exports = {
|
|
1638
1807
|
Openid4vpClient,
|