@sphereon/oid4vci-client 0.17.0 → 0.17.1-feature.esm.cjs.25
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.cjs +4679 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +916 -0
- package/dist/index.d.ts +916 -23
- package/dist/index.js +4613 -39
- package/dist/index.js.map +1 -1
- package/package.json +26 -17
- package/dist/AccessTokenClient.d.ts +0 -31
- package/dist/AccessTokenClient.d.ts.map +0 -1
- package/dist/AccessTokenClient.js +0 -250
- package/dist/AccessTokenClient.js.map +0 -1
- package/dist/AccessTokenClientV1_0_11.d.ts +0 -31
- package/dist/AccessTokenClientV1_0_11.d.ts.map +0 -1
- package/dist/AccessTokenClientV1_0_11.js +0 -236
- package/dist/AccessTokenClientV1_0_11.js.map +0 -1
- package/dist/AuthorizationCodeClient.d.ts +0 -24
- package/dist/AuthorizationCodeClient.d.ts.map +0 -1
- package/dist/AuthorizationCodeClient.js +0 -274
- package/dist/AuthorizationCodeClient.js.map +0 -1
- package/dist/AuthorizationCodeClientV1_0_11.d.ts +0 -9
- package/dist/AuthorizationCodeClientV1_0_11.d.ts.map +0 -1
- package/dist/AuthorizationCodeClientV1_0_11.js +0 -134
- package/dist/AuthorizationCodeClientV1_0_11.js.map +0 -1
- package/dist/AuthorizationDetailsBuilder.d.ts +0 -11
- package/dist/AuthorizationDetailsBuilder.d.ts.map +0 -1
- package/dist/AuthorizationDetailsBuilder.js +0 -44
- package/dist/AuthorizationDetailsBuilder.js.map +0 -1
- package/dist/CredentialOfferClient.d.ts +0 -10
- package/dist/CredentialOfferClient.d.ts.map +0 -1
- package/dist/CredentialOfferClient.js +0 -106
- package/dist/CredentialOfferClient.js.map +0 -1
- package/dist/CredentialOfferClientV1_0_11.d.ts +0 -10
- package/dist/CredentialOfferClientV1_0_11.d.ts.map +0 -1
- package/dist/CredentialOfferClientV1_0_11.js +0 -101
- package/dist/CredentialOfferClientV1_0_11.js.map +0 -1
- package/dist/CredentialOfferClientV1_0_13.d.ts +0 -10
- package/dist/CredentialOfferClientV1_0_13.d.ts.map +0 -1
- package/dist/CredentialOfferClientV1_0_13.js +0 -94
- package/dist/CredentialOfferClientV1_0_13.js.map +0 -1
- package/dist/CredentialRequestClient.d.ts +0 -88
- package/dist/CredentialRequestClient.d.ts.map +0 -1
- package/dist/CredentialRequestClient.js +0 -237
- package/dist/CredentialRequestClient.js.map +0 -1
- package/dist/CredentialRequestClientBuilder.d.ts +0 -44
- package/dist/CredentialRequestClientBuilder.d.ts.map +0 -1
- package/dist/CredentialRequestClientBuilder.js +0 -158
- package/dist/CredentialRequestClientBuilder.js.map +0 -1
- package/dist/CredentialRequestClientBuilderV1_0_11.d.ts +0 -50
- package/dist/CredentialRequestClientBuilderV1_0_11.d.ts.map +0 -1
- package/dist/CredentialRequestClientBuilderV1_0_11.js +0 -125
- package/dist/CredentialRequestClientBuilderV1_0_11.js.map +0 -1
- package/dist/CredentialRequestClientBuilderV1_0_13.d.ts +0 -53
- package/dist/CredentialRequestClientBuilderV1_0_13.d.ts.map +0 -1
- package/dist/CredentialRequestClientBuilderV1_0_13.js +0 -135
- package/dist/CredentialRequestClientBuilderV1_0_13.js.map +0 -1
- package/dist/CredentialRequestClientV1_0_11.d.ts +0 -52
- package/dist/CredentialRequestClientV1_0_11.d.ts.map +0 -1
- package/dist/CredentialRequestClientV1_0_11.js +0 -179
- package/dist/CredentialRequestClientV1_0_11.js.map +0 -1
- package/dist/MetadataClient.d.ts +0 -32
- package/dist/MetadataClient.d.ts.map +0 -1
- package/dist/MetadataClient.js +0 -206
- package/dist/MetadataClient.js.map +0 -1
- package/dist/MetadataClientV1_0_11.d.ts +0 -31
- package/dist/MetadataClientV1_0_11.d.ts.map +0 -1
- package/dist/MetadataClientV1_0_11.js +0 -189
- package/dist/MetadataClientV1_0_11.js.map +0 -1
- package/dist/MetadataClientV1_0_13.d.ts +0 -32
- package/dist/MetadataClientV1_0_13.d.ts.map +0 -1
- package/dist/MetadataClientV1_0_13.js +0 -189
- package/dist/MetadataClientV1_0_13.js.map +0 -1
- package/dist/OpenID4VCIClient.d.ts +0 -110
- package/dist/OpenID4VCIClient.d.ts.map +0 -1
- package/dist/OpenID4VCIClient.js +0 -565
- package/dist/OpenID4VCIClient.js.map +0 -1
- package/dist/OpenID4VCIClientV1_0_11.d.ts +0 -113
- package/dist/OpenID4VCIClientV1_0_11.d.ts.map +0 -1
- package/dist/OpenID4VCIClientV1_0_11.js +0 -497
- package/dist/OpenID4VCIClientV1_0_11.js.map +0 -1
- package/dist/OpenID4VCIClientV1_0_13.d.ts +0 -135
- package/dist/OpenID4VCIClientV1_0_13.d.ts.map +0 -1
- package/dist/OpenID4VCIClientV1_0_13.js +0 -567
- package/dist/OpenID4VCIClientV1_0_13.js.map +0 -1
- package/dist/ProofOfPossessionBuilder.d.ts +0 -52
- package/dist/ProofOfPossessionBuilder.d.ts.map +0 -1
- package/dist/ProofOfPossessionBuilder.js +0 -150
- package/dist/ProofOfPossessionBuilder.js.map +0 -1
- package/dist/functions/AccessTokenUtil.d.ts +0 -5
- package/dist/functions/AccessTokenUtil.d.ts.map +0 -1
- package/dist/functions/AccessTokenUtil.js +0 -63
- package/dist/functions/AccessTokenUtil.js.map +0 -1
- package/dist/functions/AuthorizationUtil.d.ts +0 -3
- package/dist/functions/AuthorizationUtil.d.ts.map +0 -1
- package/dist/functions/AuthorizationUtil.js +0 -22
- package/dist/functions/AuthorizationUtil.js.map +0 -1
- package/dist/functions/CredentialOfferCommons.d.ts +0 -19
- package/dist/functions/CredentialOfferCommons.d.ts.map +0 -1
- package/dist/functions/CredentialOfferCommons.js +0 -50
- package/dist/functions/CredentialOfferCommons.js.map +0 -1
- package/dist/functions/OpenIDUtils.d.ts +0 -12
- package/dist/functions/OpenIDUtils.d.ts.map +0 -1
- package/dist/functions/OpenIDUtils.js +0 -37
- package/dist/functions/OpenIDUtils.js.map +0 -1
- package/dist/functions/dpopUtil.d.ts +0 -10
- package/dist/functions/dpopUtil.d.ts.map +0 -1
- package/dist/functions/dpopUtil.js +0 -30
- package/dist/functions/dpopUtil.js.map +0 -1
- package/dist/functions/index.d.ts +0 -6
- package/dist/functions/index.d.ts.map +0 -1
- package/dist/functions/index.js +0 -22
- package/dist/functions/index.js.map +0 -1
- package/dist/functions/notifications.d.ts +0 -4
- package/dist/functions/notifications.d.ts.map +0 -1
- package/dist/functions/notifications.js +0 -38
- package/dist/functions/notifications.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/types/index.d.ts +0 -3
- package/dist/types/index.d.ts.map +0 -1
- package/dist/types/index.js +0 -7
- package/dist/types/index.js.map +0 -1
- package/lib/AccessTokenClient.ts +0 -314
- package/lib/AccessTokenClientV1_0_11.ts +0 -295
- package/lib/AuthorizationCodeClient.ts +0 -360
- package/lib/AuthorizationCodeClientV1_0_11.ts +0 -170
- package/lib/AuthorizationDetailsBuilder.ts +0 -46
- package/lib/CredentialOfferClient.ts +0 -116
- package/lib/CredentialOfferClientV1_0_11.ts +0 -114
- package/lib/CredentialOfferClientV1_0_13.ts +0 -98
- package/lib/CredentialRequestClient.ts +0 -356
- package/lib/CredentialRequestClientBuilder.ts +0 -208
- package/lib/CredentialRequestClientBuilderV1_0_11.ts +0 -169
- package/lib/CredentialRequestClientBuilderV1_0_13.ts +0 -182
- package/lib/CredentialRequestClientV1_0_11.ts +0 -240
- package/lib/MetadataClient.ts +0 -234
- package/lib/MetadataClientV1_0_11.ts +0 -198
- package/lib/MetadataClientV1_0_13.ts +0 -198
- package/lib/OpenID4VCIClient.ts +0 -797
- package/lib/OpenID4VCIClientV1_0_11.ts +0 -720
- package/lib/OpenID4VCIClientV1_0_13.ts +0 -828
- package/lib/ProofOfPossessionBuilder.ts +0 -234
- package/lib/__tests__/AccessTokenClient.spec.ts +0 -237
- package/lib/__tests__/AuthorizationDetailsBuilder.spec.ts +0 -53
- package/lib/__tests__/AuthzFlowType.spec.ts +0 -39
- package/lib/__tests__/CredentialRequestClient.spec.ts +0 -396
- package/lib/__tests__/CredentialRequestClientBuilder.spec.ts +0 -167
- package/lib/__tests__/CredentialRequestClientV1_0_11.spec.ts +0 -413
- package/lib/__tests__/EBSIE2E.spec.test.ts +0 -145
- package/lib/__tests__/HttpUtils.spec.ts +0 -37
- package/lib/__tests__/IT.spec.ts +0 -455
- package/lib/__tests__/IssuanceInitiation.spec.ts +0 -116
- package/lib/__tests__/IssuanceInitiationV1_0_11.spec.ts +0 -62
- package/lib/__tests__/JsonURIConversions.spec.ts +0 -146
- package/lib/__tests__/MattrE2E.spec.test.ts +0 -104
- package/lib/__tests__/MetadataClient.spec.ts +0 -332
- package/lib/__tests__/MetadataMocks.ts +0 -524
- package/lib/__tests__/OpenID4VCIClient.spec.ts +0 -280
- package/lib/__tests__/OpenID4VCIClientPARV1_0_11.spec.ts +0 -122
- package/lib/__tests__/OpenID4VCIClientV1_0_11.spec.ts +0 -269
- package/lib/__tests__/OpenID4VCIClientV1_0_13.spec.ts +0 -226
- package/lib/__tests__/ProofOfPossessionBuilder.spec.ts +0 -195
- package/lib/__tests__/SdJwt.spec.ts +0 -285
- package/lib/__tests__/SphereonE2E.spec.test.ts +0 -172
- package/lib/__tests__/data/VciDataFixtures.ts +0 -1431
- package/lib/functions/AccessTokenUtil.ts +0 -52
- package/lib/functions/AuthorizationUtil.ts +0 -18
- package/lib/functions/CredentialOfferCommons.ts +0 -52
- package/lib/functions/OpenIDUtils.ts +0 -25
- package/lib/functions/dpopUtil.ts +0 -35
- package/lib/functions/index.ts +0 -5
- package/lib/functions/notifications.ts +0 -30
- package/lib/index.ts +0 -25
- package/lib/types/index.ts +0 -6
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,4679 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
9
|
+
var __export = (target, all) => {
|
|
10
|
+
for (var name in all)
|
|
11
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
12
|
+
};
|
|
13
|
+
var __copyProps = (to, from, except, desc) => {
|
|
14
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
15
|
+
for (let key of __getOwnPropNames(from))
|
|
16
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
17
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
18
|
+
}
|
|
19
|
+
return to;
|
|
20
|
+
};
|
|
21
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
22
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
23
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
24
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
25
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
26
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
27
|
+
mod
|
|
28
|
+
));
|
|
29
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
30
|
+
|
|
31
|
+
// lib/index.ts
|
|
32
|
+
var index_exports = {};
|
|
33
|
+
__export(index_exports, {
|
|
34
|
+
AccessTokenClient: () => AccessTokenClient,
|
|
35
|
+
AccessTokenClientV1_0_11: () => AccessTokenClientV1_0_11,
|
|
36
|
+
CredentialOfferClient: () => CredentialOfferClient,
|
|
37
|
+
CredentialOfferClientV1_0_11: () => CredentialOfferClientV1_0_11,
|
|
38
|
+
CredentialOfferClientV1_0_13: () => CredentialOfferClientV1_0_13,
|
|
39
|
+
CredentialRequestClient: () => CredentialRequestClient,
|
|
40
|
+
CredentialRequestClientBuilder: () => CredentialRequestClientBuilder,
|
|
41
|
+
CredentialRequestClientBuilderV1_0_11: () => CredentialRequestClientBuilderV1_0_11,
|
|
42
|
+
CredentialRequestClientBuilderV1_0_13: () => CredentialRequestClientBuilderV1_0_13,
|
|
43
|
+
CredentialRequestClientV1_0_11: () => CredentialRequestClientV1_0_11,
|
|
44
|
+
LOG: () => LOG2,
|
|
45
|
+
MetadataClient: () => MetadataClient,
|
|
46
|
+
MetadataClientV1_0_11: () => MetadataClientV1_0_11,
|
|
47
|
+
MetadataClientV1_0_13: () => MetadataClientV1_0_13,
|
|
48
|
+
OpenID4VCIClient: () => OpenID4VCIClient,
|
|
49
|
+
OpenID4VCIClientV1_0_11: () => OpenID4VCIClientV1_0_11,
|
|
50
|
+
OpenID4VCIClientV1_0_13: () => OpenID4VCIClientV1_0_13,
|
|
51
|
+
ProofOfPossessionBuilder: () => ProofOfPossessionBuilder,
|
|
52
|
+
acquireAuthorizationChallengeAuthCode: () => acquireAuthorizationChallengeAuthCode,
|
|
53
|
+
acquireAuthorizationChallengeAuthCodeUsingRequest: () => acquireAuthorizationChallengeAuthCodeUsingRequest,
|
|
54
|
+
buildProof: () => buildProof,
|
|
55
|
+
constructBaseResponse: () => constructBaseResponse,
|
|
56
|
+
createAuthorizationChallengeRequest: () => createAuthorizationChallengeRequest,
|
|
57
|
+
createAuthorizationRequestUrl: () => createAuthorizationRequestUrl,
|
|
58
|
+
createAuthorizationRequestUrlV1_0_11: () => createAuthorizationRequestUrlV1_0_11,
|
|
59
|
+
createJwtBearerClientAssertion: () => createJwtBearerClientAssertion,
|
|
60
|
+
createSignedAuthRequestWhenNeeded: () => createSignedAuthRequestWhenNeeded,
|
|
61
|
+
generateMissingPKCEOpts: () => generateMissingPKCEOpts,
|
|
62
|
+
handleCredentialOfferUri: () => handleCredentialOfferUri,
|
|
63
|
+
isUriEncoded: () => isUriEncoded,
|
|
64
|
+
retrieveWellknown: () => retrieveWellknown,
|
|
65
|
+
sendAuthorizationChallengeRequest: () => sendAuthorizationChallengeRequest,
|
|
66
|
+
sendNotification: () => sendNotification
|
|
67
|
+
});
|
|
68
|
+
module.exports = __toCommonJS(index_exports);
|
|
69
|
+
var import_oid4vci_common26 = require("@sphereon/oid4vci-common");
|
|
70
|
+
|
|
71
|
+
// lib/AccessTokenClient.ts
|
|
72
|
+
var import_oid4vc_common3 = require("@sphereon/oid4vc-common");
|
|
73
|
+
var import_oid4vci_common9 = require("@sphereon/oid4vci-common");
|
|
74
|
+
var import_ssi_types2 = require("@sphereon/ssi-types");
|
|
75
|
+
|
|
76
|
+
// lib/MetadataClientV1_0_13.ts
|
|
77
|
+
var import_oid4vci_common8 = require("@sphereon/oid4vci-common");
|
|
78
|
+
var import_debug2 = __toESM(require("debug"), 1);
|
|
79
|
+
|
|
80
|
+
// lib/functions/AuthorizationUtil.ts
|
|
81
|
+
var import_oid4vci_common = require("@sphereon/oid4vci-common");
|
|
82
|
+
var generateMissingPKCEOpts = /* @__PURE__ */ __name((pkce) => {
|
|
83
|
+
if (pkce.disabled) {
|
|
84
|
+
return pkce;
|
|
85
|
+
}
|
|
86
|
+
if (!pkce.codeChallengeMethod) {
|
|
87
|
+
pkce.codeChallengeMethod = import_oid4vci_common.CodeChallengeMethod.S256;
|
|
88
|
+
}
|
|
89
|
+
if (!pkce.codeVerifier) {
|
|
90
|
+
pkce.codeVerifier = (0, import_oid4vci_common.generateCodeVerifier)();
|
|
91
|
+
}
|
|
92
|
+
(0, import_oid4vci_common.assertValidCodeVerifier)(pkce.codeVerifier);
|
|
93
|
+
if (!pkce.codeChallenge) {
|
|
94
|
+
pkce.codeChallenge = (0, import_oid4vci_common.createCodeChallenge)(pkce.codeVerifier, pkce.codeChallengeMethod);
|
|
95
|
+
}
|
|
96
|
+
return pkce;
|
|
97
|
+
}, "generateMissingPKCEOpts");
|
|
98
|
+
|
|
99
|
+
// lib/functions/notifications.ts
|
|
100
|
+
var import_oid4vci_common3 = require("@sphereon/oid4vci-common");
|
|
101
|
+
|
|
102
|
+
// lib/types/index.ts
|
|
103
|
+
var import_oid4vci_common2 = require("@sphereon/oid4vci-common");
|
|
104
|
+
var import_ssi_types = require("@sphereon/ssi-types");
|
|
105
|
+
var LOG = import_oid4vci_common2.VCI_LOGGERS.options("sphereon:oid4vci:client", {
|
|
106
|
+
methods: [
|
|
107
|
+
import_ssi_types.LogMethod.EVENT,
|
|
108
|
+
import_ssi_types.LogMethod.DEBUG_PKG
|
|
109
|
+
]
|
|
110
|
+
}).get("sphereon:oid4vci:client");
|
|
111
|
+
|
|
112
|
+
// lib/functions/notifications.ts
|
|
113
|
+
async function sendNotification(credentialRequestOpts, request, accessToken) {
|
|
114
|
+
LOG.info(`Sending status notification event '${request.event}' for id ${request.notification_id}`);
|
|
115
|
+
if (!credentialRequestOpts.notificationEndpoint) {
|
|
116
|
+
throw Error(`Cannot send notification when no notification endpoint is provided`);
|
|
117
|
+
}
|
|
118
|
+
const token = accessToken ?? credentialRequestOpts.token;
|
|
119
|
+
const response = await (0, import_oid4vci_common3.post)(credentialRequestOpts.notificationEndpoint, JSON.stringify(request), {
|
|
120
|
+
...token && {
|
|
121
|
+
bearerToken: token
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
const error = response.errorBody?.error !== void 0;
|
|
125
|
+
const result = {
|
|
126
|
+
error,
|
|
127
|
+
response: error ? response.errorBody : void 0
|
|
128
|
+
};
|
|
129
|
+
if (error) {
|
|
130
|
+
LOG.warning(`Notification endpoint returned an error for event '${request.event}' and id ${request.notification_id}: ${response.errorBody}`);
|
|
131
|
+
} else {
|
|
132
|
+
LOG.debug(`Notification endpoint returned success for event '${request.event}' and id ${request.notification_id}`);
|
|
133
|
+
}
|
|
134
|
+
return result;
|
|
135
|
+
}
|
|
136
|
+
__name(sendNotification, "sendNotification");
|
|
137
|
+
|
|
138
|
+
// lib/functions/OpenIDUtils.ts
|
|
139
|
+
var import_oid4vci_common4 = require("@sphereon/oid4vci-common");
|
|
140
|
+
var import_debug = __toESM(require("debug"), 1);
|
|
141
|
+
var debug = (0, import_debug.default)("sphereon:openid4vci:openid-utils");
|
|
142
|
+
var retrieveWellknown = /* @__PURE__ */ __name(async (host, endpointType, opts) => {
|
|
143
|
+
const result = await (0, import_oid4vci_common4.getJson)(`${host.endsWith("/") ? host.slice(0, -1) : host}${endpointType}`, {
|
|
144
|
+
exceptionOnHttpErrorStatus: opts?.errorOnNotFound
|
|
145
|
+
});
|
|
146
|
+
if (result.origResponse.status >= 400) {
|
|
147
|
+
debug(`host ${host} with endpoint type ${endpointType} status: ${result.origResponse.status}, ${result.origResponse.statusText}`);
|
|
148
|
+
}
|
|
149
|
+
return result;
|
|
150
|
+
}, "retrieveWellknown");
|
|
151
|
+
|
|
152
|
+
// lib/functions/AccessTokenUtil.ts
|
|
153
|
+
var import_oid4vc_common = require("@sphereon/oid4vc-common");
|
|
154
|
+
var import_oid4vci_common6 = require("@sphereon/oid4vci-common");
|
|
155
|
+
|
|
156
|
+
// lib/ProofOfPossessionBuilder.ts
|
|
157
|
+
var import_oid4vci_common5 = require("@sphereon/oid4vci-common");
|
|
158
|
+
var ProofOfPossessionBuilder = class _ProofOfPossessionBuilder {
|
|
159
|
+
static {
|
|
160
|
+
__name(this, "ProofOfPossessionBuilder");
|
|
161
|
+
}
|
|
162
|
+
proof;
|
|
163
|
+
callbacks;
|
|
164
|
+
version;
|
|
165
|
+
mode = "pop";
|
|
166
|
+
kid;
|
|
167
|
+
jwk;
|
|
168
|
+
aud;
|
|
169
|
+
clientId;
|
|
170
|
+
issuer;
|
|
171
|
+
jwt;
|
|
172
|
+
alg;
|
|
173
|
+
jti;
|
|
174
|
+
cNonce;
|
|
175
|
+
typ;
|
|
176
|
+
constructor({ proof, callbacks, jwt, accessTokenResponse, version, mode = "pop" }) {
|
|
177
|
+
this.mode = mode;
|
|
178
|
+
this.proof = proof;
|
|
179
|
+
this.callbacks = callbacks;
|
|
180
|
+
this.version = version;
|
|
181
|
+
if (jwt) {
|
|
182
|
+
this.withJwt(jwt);
|
|
183
|
+
} else {
|
|
184
|
+
this.withTyp(version < import_oid4vci_common5.OpenId4VCIVersion.VER_1_0_11 || mode === "JWT" ? "JWT" : "openid4vci-proof+jwt");
|
|
185
|
+
}
|
|
186
|
+
if (accessTokenResponse) {
|
|
187
|
+
this.withAccessTokenResponse(accessTokenResponse);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
static manual({ jwt, callbacks, version, mode = "JWT" }) {
|
|
191
|
+
return new _ProofOfPossessionBuilder({
|
|
192
|
+
callbacks,
|
|
193
|
+
jwt,
|
|
194
|
+
version,
|
|
195
|
+
mode
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
static fromJwt({ jwt, callbacks, version, mode = "pop" }) {
|
|
199
|
+
return new _ProofOfPossessionBuilder({
|
|
200
|
+
callbacks,
|
|
201
|
+
jwt,
|
|
202
|
+
version,
|
|
203
|
+
mode
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
static fromAccessTokenResponse({ accessTokenResponse, callbacks, version, mode = "pop" }) {
|
|
207
|
+
return new _ProofOfPossessionBuilder({
|
|
208
|
+
callbacks,
|
|
209
|
+
accessTokenResponse,
|
|
210
|
+
version,
|
|
211
|
+
mode
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
static fromProof(proof, version) {
|
|
215
|
+
return new _ProofOfPossessionBuilder({
|
|
216
|
+
proof,
|
|
217
|
+
version
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
withAud(aud) {
|
|
221
|
+
this.aud = aud;
|
|
222
|
+
return this;
|
|
223
|
+
}
|
|
224
|
+
withClientId(clientId) {
|
|
225
|
+
this.clientId = clientId;
|
|
226
|
+
return this;
|
|
227
|
+
}
|
|
228
|
+
withKid(kid) {
|
|
229
|
+
this.kid = kid;
|
|
230
|
+
return this;
|
|
231
|
+
}
|
|
232
|
+
withJWK(jwk) {
|
|
233
|
+
this.jwk = jwk;
|
|
234
|
+
return this;
|
|
235
|
+
}
|
|
236
|
+
withIssuer(issuer) {
|
|
237
|
+
this.issuer = issuer;
|
|
238
|
+
return this;
|
|
239
|
+
}
|
|
240
|
+
withAlg(alg) {
|
|
241
|
+
this.alg = alg;
|
|
242
|
+
return this;
|
|
243
|
+
}
|
|
244
|
+
withJti(jti) {
|
|
245
|
+
this.jti = jti;
|
|
246
|
+
return this;
|
|
247
|
+
}
|
|
248
|
+
withTyp(typ) {
|
|
249
|
+
if (this.mode === "pop" && this.version >= import_oid4vci_common5.OpenId4VCIVersion.VER_1_0_11) {
|
|
250
|
+
if (!!typ && typ !== "openid4vci-proof+jwt") {
|
|
251
|
+
throw Error(`typ must be openid4vci-proof+jwt for version 1.0.11 and up. Provided: ${typ}`);
|
|
252
|
+
}
|
|
253
|
+
} else {
|
|
254
|
+
if (!!typ && typ !== "JWT") {
|
|
255
|
+
throw Error(`typ must be jwt for version 1.0.10 and below. Provided: ${typ}`);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
this.typ = typ;
|
|
259
|
+
return this;
|
|
260
|
+
}
|
|
261
|
+
withAccessTokenNonce(cNonce) {
|
|
262
|
+
this.cNonce = cNonce;
|
|
263
|
+
return this;
|
|
264
|
+
}
|
|
265
|
+
withAccessTokenResponse(accessToken) {
|
|
266
|
+
if (accessToken.c_nonce) {
|
|
267
|
+
this.withAccessTokenNonce(accessToken.c_nonce);
|
|
268
|
+
}
|
|
269
|
+
return this;
|
|
270
|
+
}
|
|
271
|
+
withEndpointMetadata(endpointMetadata) {
|
|
272
|
+
this.withIssuer(endpointMetadata.issuer);
|
|
273
|
+
return this;
|
|
274
|
+
}
|
|
275
|
+
withJwt(jwt) {
|
|
276
|
+
if (!jwt) {
|
|
277
|
+
throw new Error(import_oid4vci_common5.NO_JWT_PROVIDED);
|
|
278
|
+
}
|
|
279
|
+
this.jwt = jwt;
|
|
280
|
+
if (!jwt.header) {
|
|
281
|
+
throw Error(`No JWT header present`);
|
|
282
|
+
} else if (!jwt.payload) {
|
|
283
|
+
throw Error(`No JWT payload present`);
|
|
284
|
+
}
|
|
285
|
+
if (jwt.header.kid) {
|
|
286
|
+
this.withKid(jwt.header.kid);
|
|
287
|
+
}
|
|
288
|
+
if (jwt.header.typ) {
|
|
289
|
+
this.withTyp(jwt.header.typ);
|
|
290
|
+
}
|
|
291
|
+
if (!this.typ && this.version >= import_oid4vci_common5.OpenId4VCIVersion.VER_1_0_11) {
|
|
292
|
+
this.withTyp("openid4vci-proof+jwt");
|
|
293
|
+
}
|
|
294
|
+
this.withAlg(jwt.header.alg);
|
|
295
|
+
if (Array.isArray(jwt.payload.aud)) {
|
|
296
|
+
throw Error("We cannot handle multiple aud values currently");
|
|
297
|
+
}
|
|
298
|
+
if (jwt.payload) {
|
|
299
|
+
if (jwt.payload.iss) this.mode === "pop" ? this.withClientId(jwt.payload.iss) : this.withIssuer(jwt.payload.iss);
|
|
300
|
+
if (jwt.payload.aud) this.mode === "pop" ? this.withIssuer(jwt.payload.aud) : this.withAud(jwt.payload.aud);
|
|
301
|
+
if (jwt.payload.jti) this.withJti(jwt.payload.jti);
|
|
302
|
+
if (jwt.payload.nonce) this.withAccessTokenNonce(jwt.payload.nonce);
|
|
303
|
+
}
|
|
304
|
+
return this;
|
|
305
|
+
}
|
|
306
|
+
async build() {
|
|
307
|
+
if (this.proof) {
|
|
308
|
+
return Promise.resolve(this.proof);
|
|
309
|
+
} else if (this.callbacks) {
|
|
310
|
+
return await (0, import_oid4vci_common5.createProofOfPossession)(this.mode, this.callbacks, {
|
|
311
|
+
typ: this.typ ?? (this.version < import_oid4vci_common5.OpenId4VCIVersion.VER_1_0_11 || this.mode === "JWT" ? "JWT" : "openid4vci-proof+jwt"),
|
|
312
|
+
kid: this.kid,
|
|
313
|
+
jwk: this.jwk,
|
|
314
|
+
jti: this.jti,
|
|
315
|
+
alg: this.alg,
|
|
316
|
+
aud: this.aud,
|
|
317
|
+
issuer: this.issuer,
|
|
318
|
+
clientId: this.clientId,
|
|
319
|
+
...this.cNonce && {
|
|
320
|
+
nonce: this.cNonce
|
|
321
|
+
}
|
|
322
|
+
}, this.jwt);
|
|
323
|
+
}
|
|
324
|
+
throw new Error(import_oid4vci_common5.PROOF_CANT_BE_CONSTRUCTED);
|
|
325
|
+
}
|
|
326
|
+
};
|
|
327
|
+
|
|
328
|
+
// lib/functions/AccessTokenUtil.ts
|
|
329
|
+
var createJwtBearerClientAssertion = /* @__PURE__ */ __name(async (request, opts) => {
|
|
330
|
+
const { asOpts, credentialIssuer } = opts;
|
|
331
|
+
if (asOpts?.clientOpts?.clientAssertionType === "urn:ietf:params:oauth:client-assertion-type:jwt-bearer") {
|
|
332
|
+
const { clientId = request.client_id, signCallbacks, alg } = asOpts.clientOpts;
|
|
333
|
+
let { kid } = asOpts.clientOpts;
|
|
334
|
+
if (!clientId) {
|
|
335
|
+
return Promise.reject(Error(`Not client_id supplied, but client-assertion jwt-bearer requested.`));
|
|
336
|
+
} else if (!kid) {
|
|
337
|
+
return Promise.reject(Error(`No kid supplied, but client-assertion jwt-bearer requested.`));
|
|
338
|
+
} else if (typeof signCallbacks?.signCallback !== "function") {
|
|
339
|
+
return Promise.reject(Error(`No sign callback supplied, but client-assertion jwt-bearer requested.`));
|
|
340
|
+
} else if (!credentialIssuer) {
|
|
341
|
+
return Promise.reject(Error(`No credential issuer supplied, but client-assertion jwt-bearer requested.`));
|
|
342
|
+
}
|
|
343
|
+
if (clientId.startsWith("http") && kid.includes("#")) {
|
|
344
|
+
kid = kid.split("#")[1];
|
|
345
|
+
}
|
|
346
|
+
const jwt = {
|
|
347
|
+
header: {
|
|
348
|
+
typ: "JWT",
|
|
349
|
+
kid,
|
|
350
|
+
alg: alg ?? "ES256"
|
|
351
|
+
},
|
|
352
|
+
payload: {
|
|
353
|
+
iss: clientId,
|
|
354
|
+
sub: clientId,
|
|
355
|
+
aud: credentialIssuer,
|
|
356
|
+
jti: (0, import_oid4vc_common.uuidv4)(),
|
|
357
|
+
exp: Math.floor(Date.now()) / 1e3 + 60,
|
|
358
|
+
iat: Math.floor(Date.now()) / 1e3 - 60
|
|
359
|
+
}
|
|
360
|
+
};
|
|
361
|
+
const pop = await ProofOfPossessionBuilder.fromJwt({
|
|
362
|
+
jwt,
|
|
363
|
+
callbacks: signCallbacks,
|
|
364
|
+
version: opts.version ?? import_oid4vci_common6.OpenId4VCIVersion.VER_1_0_13,
|
|
365
|
+
mode: "JWT"
|
|
366
|
+
}).build();
|
|
367
|
+
request.client_assertion_type = "urn:ietf:params:oauth:client-assertion-type:jwt-bearer";
|
|
368
|
+
request.client_assertion = pop.jwt;
|
|
369
|
+
}
|
|
370
|
+
}, "createJwtBearerClientAssertion");
|
|
371
|
+
|
|
372
|
+
// lib/functions/CredentialOfferCommons.ts
|
|
373
|
+
var import_oid4vci_common7 = require("@sphereon/oid4vci-common");
|
|
374
|
+
var import_cross_fetch = require("cross-fetch");
|
|
375
|
+
function isUriEncoded(str) {
|
|
376
|
+
const pattern = /%[0-9A-F]{2}/i;
|
|
377
|
+
return pattern.test(str);
|
|
378
|
+
}
|
|
379
|
+
__name(isUriEncoded, "isUriEncoded");
|
|
380
|
+
async function handleCredentialOfferUri(uri) {
|
|
381
|
+
const uriObj = (0, import_oid4vci_common7.getURIComponentsAsArray)(uri);
|
|
382
|
+
const credentialOfferUri = decodeURIComponent(uriObj["credential_offer_uri"]);
|
|
383
|
+
const decodedUri = isUriEncoded(credentialOfferUri) ? decodeURIComponent(credentialOfferUri) : credentialOfferUri;
|
|
384
|
+
const response = await (0, import_cross_fetch.fetch)(decodedUri);
|
|
385
|
+
if (!(response && response.status >= 200 && response.status < 400)) {
|
|
386
|
+
return Promise.reject(`the credential offer URI endpoint call was not successful. http code ${response.status} - reason ${response.statusText}`);
|
|
387
|
+
}
|
|
388
|
+
if (response.headers.get("Content-Type")?.startsWith("application/json") === false) {
|
|
389
|
+
return Promise.reject("the credential offer URI endpoint did not return content type application/json");
|
|
390
|
+
}
|
|
391
|
+
return {
|
|
392
|
+
credential_offer: (0, import_oid4vci_common7.decodeJsonProperties)(await response.json())
|
|
393
|
+
};
|
|
394
|
+
}
|
|
395
|
+
__name(handleCredentialOfferUri, "handleCredentialOfferUri");
|
|
396
|
+
function constructBaseResponse(request, scheme, baseUrl) {
|
|
397
|
+
const clientId = (0, import_oid4vci_common7.getClientIdFromCredentialOfferPayload)(request.credential_offer);
|
|
398
|
+
const grants = request.credential_offer?.grants;
|
|
399
|
+
return {
|
|
400
|
+
scheme,
|
|
401
|
+
baseUrl,
|
|
402
|
+
...clientId && {
|
|
403
|
+
clientId
|
|
404
|
+
},
|
|
405
|
+
...request,
|
|
406
|
+
...grants?.authorization_code?.issuer_state && {
|
|
407
|
+
issuerState: grants.authorization_code.issuer_state
|
|
408
|
+
},
|
|
409
|
+
...grants?.[import_oid4vci_common7.PRE_AUTH_GRANT_LITERAL]?.[import_oid4vci_common7.PRE_AUTH_CODE_LITERAL] && {
|
|
410
|
+
preAuthorizedCode: grants[import_oid4vci_common7.PRE_AUTH_GRANT_LITERAL][import_oid4vci_common7.PRE_AUTH_CODE_LITERAL]
|
|
411
|
+
},
|
|
412
|
+
...request.credential_offer?.grants?.[import_oid4vci_common7.PRE_AUTH_GRANT_LITERAL]?.tx_code && {
|
|
413
|
+
txCode: request.credential_offer.grants[import_oid4vci_common7.PRE_AUTH_GRANT_LITERAL].tx_code
|
|
414
|
+
}
|
|
415
|
+
};
|
|
416
|
+
}
|
|
417
|
+
__name(constructBaseResponse, "constructBaseResponse");
|
|
418
|
+
|
|
419
|
+
// lib/MetadataClientV1_0_13.ts
|
|
420
|
+
var debug2 = (0, import_debug2.default)("sphereon:oid4vci:metadata");
|
|
421
|
+
var MetadataClientV1_0_13 = class _MetadataClientV1_0_13 {
|
|
422
|
+
static {
|
|
423
|
+
__name(this, "MetadataClientV1_0_13");
|
|
424
|
+
}
|
|
425
|
+
/**
|
|
426
|
+
* Retrieve metadata using the Initiation obtained from a previous step
|
|
427
|
+
*
|
|
428
|
+
* @param credentialOffer
|
|
429
|
+
*/
|
|
430
|
+
static async retrieveAllMetadataFromCredentialOffer(credentialOffer) {
|
|
431
|
+
return _MetadataClientV1_0_13.retrieveAllMetadataFromCredentialOfferRequest(credentialOffer.credential_offer);
|
|
432
|
+
}
|
|
433
|
+
/**
|
|
434
|
+
* Retrieve the metada using the initiation request obtained from a previous step
|
|
435
|
+
* @param request
|
|
436
|
+
*/
|
|
437
|
+
static async retrieveAllMetadataFromCredentialOfferRequest(request) {
|
|
438
|
+
const issuer = (0, import_oid4vci_common8.getIssuerFromCredentialOfferPayload)(request);
|
|
439
|
+
if (issuer) {
|
|
440
|
+
return _MetadataClientV1_0_13.retrieveAllMetadata(issuer);
|
|
441
|
+
}
|
|
442
|
+
throw new Error("can't retrieve metadata from CredentialOfferRequest. No issuer field is present");
|
|
443
|
+
}
|
|
444
|
+
/**
|
|
445
|
+
* Retrieve all metadata from an issuer
|
|
446
|
+
* @param issuer The issuer URL
|
|
447
|
+
* @param opts
|
|
448
|
+
*/
|
|
449
|
+
static async retrieveAllMetadata(issuer, opts) {
|
|
450
|
+
let token_endpoint;
|
|
451
|
+
let credential_endpoint;
|
|
452
|
+
let deferred_credential_endpoint;
|
|
453
|
+
let authorization_endpoint;
|
|
454
|
+
let authorization_challenge_endpoint;
|
|
455
|
+
let authorizationServerType = "OID4VCI";
|
|
456
|
+
let authorization_servers = [
|
|
457
|
+
issuer
|
|
458
|
+
];
|
|
459
|
+
const oid4vciResponse = await _MetadataClientV1_0_13.retrieveOpenID4VCIServerMetadata(issuer, {
|
|
460
|
+
errorOnNotFound: false
|
|
461
|
+
});
|
|
462
|
+
let credentialIssuerMetadata = oid4vciResponse?.successBody;
|
|
463
|
+
if (credentialIssuerMetadata) {
|
|
464
|
+
debug2(`Issuer ${issuer} OID4VCI well-known server metadata\r
|
|
465
|
+
${JSON.stringify(credentialIssuerMetadata)}`);
|
|
466
|
+
credential_endpoint = credentialIssuerMetadata.credential_endpoint;
|
|
467
|
+
deferred_credential_endpoint = credentialIssuerMetadata.deferred_credential_endpoint;
|
|
468
|
+
if (credentialIssuerMetadata.token_endpoint) {
|
|
469
|
+
token_endpoint = credentialIssuerMetadata.token_endpoint;
|
|
470
|
+
}
|
|
471
|
+
authorization_challenge_endpoint = credentialIssuerMetadata.authorization_challenge_endpoint;
|
|
472
|
+
if (credentialIssuerMetadata.authorization_servers) {
|
|
473
|
+
authorization_servers = credentialIssuerMetadata.authorization_servers;
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
let response = await retrieveWellknown(authorization_servers[0], import_oid4vci_common8.WellKnownEndpoints.OPENID_CONFIGURATION, {
|
|
477
|
+
errorOnNotFound: false
|
|
478
|
+
});
|
|
479
|
+
let authMetadata = response.successBody;
|
|
480
|
+
if (authMetadata) {
|
|
481
|
+
debug2(`Issuer ${issuer} has OpenID Connect Server metadata in well-known location`);
|
|
482
|
+
authorizationServerType = "OIDC";
|
|
483
|
+
} else {
|
|
484
|
+
response = await retrieveWellknown(authorization_servers[0], import_oid4vci_common8.WellKnownEndpoints.OAUTH_AS, {
|
|
485
|
+
errorOnNotFound: false
|
|
486
|
+
});
|
|
487
|
+
authMetadata = response.successBody;
|
|
488
|
+
}
|
|
489
|
+
if (!authMetadata) {
|
|
490
|
+
if (!authorization_servers.includes(issuer)) {
|
|
491
|
+
throw Error(`Issuer ${issuer} provided a separate authorization server ${authorization_servers}, but that server did not provide metadata`);
|
|
492
|
+
}
|
|
493
|
+
} else {
|
|
494
|
+
if (!authorizationServerType) {
|
|
495
|
+
authorizationServerType = "OAuth 2.0";
|
|
496
|
+
}
|
|
497
|
+
debug2(`Issuer ${issuer} has ${authorizationServerType} Server metadata in well-known location`);
|
|
498
|
+
if (!authMetadata.authorization_endpoint) {
|
|
499
|
+
console.warn(`Issuer ${issuer} of type ${authorizationServerType} has no authorization_endpoint! Will use ${authorization_endpoint}. This only works for pre-authorized flows`);
|
|
500
|
+
} else if (authorization_endpoint && authMetadata.authorization_endpoint !== authorization_endpoint) {
|
|
501
|
+
throw Error(`Credential issuer has a different authorization_endpoint (${authorization_endpoint}) from the Authorization Server (${authMetadata.authorization_endpoint})`);
|
|
502
|
+
}
|
|
503
|
+
authorization_endpoint = authMetadata.authorization_endpoint;
|
|
504
|
+
if (authorization_challenge_endpoint && authMetadata.authorization_challenge_endpoint !== authorization_challenge_endpoint) {
|
|
505
|
+
throw Error(`Credential issuer has a different authorization_challenge_endpoint (${authorization_challenge_endpoint}) from the Authorization Server (${authMetadata.authorization_challenge_endpoint})`);
|
|
506
|
+
}
|
|
507
|
+
authorization_challenge_endpoint = authMetadata.authorization_challenge_endpoint;
|
|
508
|
+
if (!authMetadata.token_endpoint) {
|
|
509
|
+
throw Error(`Authorization Server ${authorization_servers} did not provide a token_endpoint`);
|
|
510
|
+
} else if (token_endpoint && authMetadata.token_endpoint !== token_endpoint) {
|
|
511
|
+
throw Error(`Credential issuer has a different token_endpoint (${token_endpoint}) from the Authorization Server (${authMetadata.token_endpoint})`);
|
|
512
|
+
}
|
|
513
|
+
token_endpoint = authMetadata.token_endpoint;
|
|
514
|
+
if (authMetadata.credential_endpoint) {
|
|
515
|
+
if (credential_endpoint && authMetadata.credential_endpoint !== credential_endpoint) {
|
|
516
|
+
debug2(`Credential issuer has a different credential_endpoint (${credential_endpoint}) from the Authorization Server (${authMetadata.credential_endpoint}). Will use the issuer value`);
|
|
517
|
+
} else {
|
|
518
|
+
credential_endpoint = authMetadata.credential_endpoint;
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
if (authMetadata.deferred_credential_endpoint) {
|
|
522
|
+
if (deferred_credential_endpoint && authMetadata.deferred_credential_endpoint !== deferred_credential_endpoint) {
|
|
523
|
+
debug2(`Credential issuer has a different deferred_credential_endpoint (${deferred_credential_endpoint}) from the Authorization Server (${authMetadata.deferred_credential_endpoint}). Will use the issuer value`);
|
|
524
|
+
} else {
|
|
525
|
+
deferred_credential_endpoint = authMetadata.deferred_credential_endpoint;
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
if (!authorization_endpoint) {
|
|
530
|
+
debug2(`Issuer ${issuer} does not expose authorization_endpoint, so only pre-auth will be supported`);
|
|
531
|
+
}
|
|
532
|
+
if (!token_endpoint) {
|
|
533
|
+
debug2(`Issuer ${issuer} does not have a token_endpoint listed in well-known locations!`);
|
|
534
|
+
if (opts?.errorOnNotFound) {
|
|
535
|
+
throw Error(`Could not deduce the token_endpoint for ${issuer}`);
|
|
536
|
+
} else {
|
|
537
|
+
token_endpoint = `${issuer}${issuer.endsWith("/") ? "token" : "/token"}`;
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
if (!credential_endpoint) {
|
|
541
|
+
debug2(`Issuer ${issuer} does not have a credential_endpoint listed in well-known locations!`);
|
|
542
|
+
if (opts?.errorOnNotFound) {
|
|
543
|
+
throw Error(`Could not deduce the credential endpoint for ${issuer}`);
|
|
544
|
+
} else {
|
|
545
|
+
credential_endpoint = `${issuer}${issuer.endsWith("/") ? "credential" : "/credential"}`;
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
if (!credentialIssuerMetadata && authMetadata) {
|
|
549
|
+
credentialIssuerMetadata = authMetadata;
|
|
550
|
+
}
|
|
551
|
+
debug2(`Issuer ${issuer} token endpoint ${token_endpoint}, credential endpoint ${credential_endpoint}`);
|
|
552
|
+
return {
|
|
553
|
+
issuer,
|
|
554
|
+
token_endpoint,
|
|
555
|
+
credential_endpoint,
|
|
556
|
+
deferred_credential_endpoint,
|
|
557
|
+
authorization_server: authorization_servers[0],
|
|
558
|
+
authorization_endpoint,
|
|
559
|
+
authorization_challenge_endpoint,
|
|
560
|
+
authorizationServerType,
|
|
561
|
+
credentialIssuerMetadata,
|
|
562
|
+
authorizationServerMetadata: authMetadata
|
|
563
|
+
};
|
|
564
|
+
}
|
|
565
|
+
/**
|
|
566
|
+
* Retrieve only the OID4VCI metadata for the issuer. So no OIDC/OAuth2 metadata
|
|
567
|
+
*
|
|
568
|
+
* @param issuerHost The issuer hostname
|
|
569
|
+
* @param opts
|
|
570
|
+
*/
|
|
571
|
+
static async retrieveOpenID4VCIServerMetadata(issuerHost, opts) {
|
|
572
|
+
return retrieveWellknown(issuerHost, import_oid4vci_common8.WellKnownEndpoints.OPENID4VCI_ISSUER, {
|
|
573
|
+
errorOnNotFound: opts?.errorOnNotFound === void 0 ? true : opts.errorOnNotFound
|
|
574
|
+
});
|
|
575
|
+
}
|
|
576
|
+
};
|
|
577
|
+
|
|
578
|
+
// lib/functions/dpopUtil.ts
|
|
579
|
+
var import_oid4vc_common2 = require("@sphereon/oid4vc-common");
|
|
580
|
+
function shouldRetryTokenRequestWithDPoPNonce(response) {
|
|
581
|
+
if (!response.errorBody || response.errorBody.error !== import_oid4vc_common2.dpopTokenRequestNonceError) {
|
|
582
|
+
return {
|
|
583
|
+
ok: false
|
|
584
|
+
};
|
|
585
|
+
}
|
|
586
|
+
const dPoPNonce = response.origResponse.headers.get("DPoP-Nonce");
|
|
587
|
+
if (!dPoPNonce) {
|
|
588
|
+
throw new Error("Missing required DPoP-Nonce header.");
|
|
589
|
+
}
|
|
590
|
+
return {
|
|
591
|
+
ok: true,
|
|
592
|
+
dpopNonce: dPoPNonce
|
|
593
|
+
};
|
|
594
|
+
}
|
|
595
|
+
__name(shouldRetryTokenRequestWithDPoPNonce, "shouldRetryTokenRequestWithDPoPNonce");
|
|
596
|
+
function shouldRetryResourceRequestWithDPoPNonce(response) {
|
|
597
|
+
if (!response.errorBody || response.origResponse.status !== 401) {
|
|
598
|
+
return {
|
|
599
|
+
ok: false
|
|
600
|
+
};
|
|
601
|
+
}
|
|
602
|
+
const wwwAuthenticateHeader = response.origResponse.headers.get("WWW-Authenticate");
|
|
603
|
+
if (!wwwAuthenticateHeader?.includes(import_oid4vc_common2.dpopTokenRequestNonceError)) {
|
|
604
|
+
return {
|
|
605
|
+
ok: false
|
|
606
|
+
};
|
|
607
|
+
}
|
|
608
|
+
const dPoPNonce = response.origResponse.headers.get("DPoP-Nonce");
|
|
609
|
+
if (!dPoPNonce) {
|
|
610
|
+
throw new Error("Missing required DPoP-Nonce header.");
|
|
611
|
+
}
|
|
612
|
+
return {
|
|
613
|
+
ok: true,
|
|
614
|
+
dpopNonce: dPoPNonce
|
|
615
|
+
};
|
|
616
|
+
}
|
|
617
|
+
__name(shouldRetryResourceRequestWithDPoPNonce, "shouldRetryResourceRequestWithDPoPNonce");
|
|
618
|
+
|
|
619
|
+
// lib/AccessTokenClient.ts
|
|
620
|
+
var AccessTokenClient = class _AccessTokenClient {
|
|
621
|
+
static {
|
|
622
|
+
__name(this, "AccessTokenClient");
|
|
623
|
+
}
|
|
624
|
+
async acquireAccessToken(opts) {
|
|
625
|
+
const { asOpts, pin, codeVerifier, code, redirectUri, metadata, createDPoPOpts } = opts;
|
|
626
|
+
const credentialOffer = opts.credentialOffer ? await (0, import_oid4vci_common9.assertedUniformCredentialOffer)(opts.credentialOffer) : void 0;
|
|
627
|
+
const pinMetadata = credentialOffer && this.getPinMetadata(credentialOffer.credential_offer);
|
|
628
|
+
const issuer = opts.credentialIssuer ?? (credentialOffer ? (0, import_oid4vci_common9.getIssuerFromCredentialOfferPayload)(credentialOffer.credential_offer) : metadata?.issuer);
|
|
629
|
+
if (!issuer) {
|
|
630
|
+
throw Error("Issuer required at this point");
|
|
631
|
+
}
|
|
632
|
+
const issuerOpts = {
|
|
633
|
+
issuer
|
|
634
|
+
};
|
|
635
|
+
return await this.acquireAccessTokenUsingRequest({
|
|
636
|
+
accessTokenRequest: await this.createAccessTokenRequest({
|
|
637
|
+
credentialOffer,
|
|
638
|
+
asOpts,
|
|
639
|
+
codeVerifier,
|
|
640
|
+
code,
|
|
641
|
+
redirectUri,
|
|
642
|
+
pin,
|
|
643
|
+
credentialIssuer: issuer,
|
|
644
|
+
metadata,
|
|
645
|
+
additionalParams: opts.additionalParams,
|
|
646
|
+
pinMetadata
|
|
647
|
+
}),
|
|
648
|
+
pinMetadata,
|
|
649
|
+
metadata,
|
|
650
|
+
asOpts,
|
|
651
|
+
issuerOpts,
|
|
652
|
+
createDPoPOpts
|
|
653
|
+
});
|
|
654
|
+
}
|
|
655
|
+
async acquireAccessTokenUsingRequest({ accessTokenRequest, pinMetadata, metadata, asOpts, issuerOpts, createDPoPOpts }) {
|
|
656
|
+
this.validate(accessTokenRequest, pinMetadata);
|
|
657
|
+
const requestTokenURL = _AccessTokenClient.determineTokenURL({
|
|
658
|
+
asOpts,
|
|
659
|
+
issuerOpts,
|
|
660
|
+
metadata: metadata ? metadata : issuerOpts?.fetchMetadata ? await MetadataClientV1_0_13.retrieveAllMetadata(issuerOpts.issuer, {
|
|
661
|
+
errorOnNotFound: false
|
|
662
|
+
}) : void 0
|
|
663
|
+
});
|
|
664
|
+
const useDpop = createDPoPOpts?.dPoPSigningAlgValuesSupported && createDPoPOpts.dPoPSigningAlgValuesSupported.length > 0;
|
|
665
|
+
let dPoP = useDpop ? await (0, import_oid4vc_common3.createDPoP)((0, import_oid4vc_common3.getCreateDPoPOptions)(createDPoPOpts, requestTokenURL)) : void 0;
|
|
666
|
+
let response = await this.sendAuthCode(requestTokenURL, accessTokenRequest, dPoP ? {
|
|
667
|
+
headers: {
|
|
668
|
+
dpop: dPoP
|
|
669
|
+
}
|
|
670
|
+
} : void 0);
|
|
671
|
+
let nextDPoPNonce = createDPoPOpts?.jwtPayloadProps.nonce;
|
|
672
|
+
const retryWithNonce = shouldRetryTokenRequestWithDPoPNonce(response);
|
|
673
|
+
if (retryWithNonce.ok && createDPoPOpts) {
|
|
674
|
+
createDPoPOpts.jwtPayloadProps.nonce = retryWithNonce.dpopNonce;
|
|
675
|
+
dPoP = await (0, import_oid4vc_common3.createDPoP)((0, import_oid4vc_common3.getCreateDPoPOptions)(createDPoPOpts, requestTokenURL));
|
|
676
|
+
response = await this.sendAuthCode(requestTokenURL, accessTokenRequest, dPoP ? {
|
|
677
|
+
headers: {
|
|
678
|
+
dpop: dPoP
|
|
679
|
+
}
|
|
680
|
+
} : void 0);
|
|
681
|
+
const successDPoPNonce = response.origResponse.headers.get("DPoP-Nonce");
|
|
682
|
+
nextDPoPNonce = successDPoPNonce ?? retryWithNonce.dpopNonce;
|
|
683
|
+
}
|
|
684
|
+
if (response.successBody && createDPoPOpts && response.successBody.token_type !== "DPoP") {
|
|
685
|
+
throw new Error("Invalid token type returned. Expected DPoP. Received: " + response.successBody.token_type);
|
|
686
|
+
}
|
|
687
|
+
return {
|
|
688
|
+
...response,
|
|
689
|
+
...nextDPoPNonce && {
|
|
690
|
+
params: {
|
|
691
|
+
dpop: {
|
|
692
|
+
dpopNonce: nextDPoPNonce
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
};
|
|
697
|
+
}
|
|
698
|
+
async createAccessTokenRequest(opts) {
|
|
699
|
+
const { asOpts, pin, codeVerifier, code, redirectUri } = opts;
|
|
700
|
+
const credentialOfferRequest = opts.credentialOffer ? await (0, import_oid4vci_common9.toUniformCredentialOfferRequest)(opts.credentialOffer) : void 0;
|
|
701
|
+
const request = {
|
|
702
|
+
...opts.additionalParams
|
|
703
|
+
};
|
|
704
|
+
if (asOpts?.clientOpts?.clientId) {
|
|
705
|
+
request.client_id = asOpts.clientOpts.clientId;
|
|
706
|
+
}
|
|
707
|
+
const credentialIssuer = opts.credentialIssuer ?? credentialOfferRequest?.credential_offer?.credential_issuer ?? opts.metadata?.issuer;
|
|
708
|
+
await createJwtBearerClientAssertion(request, {
|
|
709
|
+
...opts,
|
|
710
|
+
credentialIssuer
|
|
711
|
+
});
|
|
712
|
+
if (!credentialOfferRequest || credentialOfferRequest.supportedFlows.includes(import_oid4vci_common9.AuthzFlowType.AUTHORIZATION_CODE_FLOW)) {
|
|
713
|
+
request.grant_type = import_oid4vci_common9.GrantTypes.AUTHORIZATION_CODE;
|
|
714
|
+
request.code = code;
|
|
715
|
+
request.redirect_uri = redirectUri;
|
|
716
|
+
if (codeVerifier) {
|
|
717
|
+
request.code_verifier = codeVerifier;
|
|
718
|
+
}
|
|
719
|
+
return request;
|
|
720
|
+
}
|
|
721
|
+
if (credentialOfferRequest?.supportedFlows.includes(import_oid4vci_common9.AuthzFlowType.PRE_AUTHORIZED_CODE_FLOW)) {
|
|
722
|
+
this.assertAlphanumericPin(opts.pinMetadata, pin);
|
|
723
|
+
request.user_pin = pin;
|
|
724
|
+
request.tx_code = pin;
|
|
725
|
+
request.grant_type = import_oid4vci_common9.GrantTypes.PRE_AUTHORIZED_CODE;
|
|
726
|
+
request[import_oid4vci_common9.PRE_AUTH_CODE_LITERAL] = credentialOfferRequest?.credential_offer.grants?.[import_oid4vci_common9.PRE_AUTH_GRANT_LITERAL]?.[import_oid4vci_common9.PRE_AUTH_CODE_LITERAL];
|
|
727
|
+
return request;
|
|
728
|
+
}
|
|
729
|
+
throw new Error("Credential offer request follows neither pre-authorized code nor authorization code flow requirements.");
|
|
730
|
+
}
|
|
731
|
+
assertPreAuthorizedGrantType(grantType) {
|
|
732
|
+
if (import_oid4vci_common9.GrantTypes.PRE_AUTHORIZED_CODE !== grantType) {
|
|
733
|
+
throw new Error("grant type must be 'urn:ietf:params:oauth:grant-type:pre-authorized_code'");
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
assertAuthorizationGrantType(grantType) {
|
|
737
|
+
if (import_oid4vci_common9.GrantTypes.AUTHORIZATION_CODE !== grantType) {
|
|
738
|
+
throw new Error("grant type must be 'authorization_code'");
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
getPinMetadata(requestPayload) {
|
|
742
|
+
if (!requestPayload) {
|
|
743
|
+
throw new Error(import_oid4vci_common9.TokenErrorResponse.invalid_request);
|
|
744
|
+
}
|
|
745
|
+
const issuer = (0, import_oid4vci_common9.getIssuerFromCredentialOfferPayload)(requestPayload);
|
|
746
|
+
const grantDetails = requestPayload.grants?.[import_oid4vci_common9.PRE_AUTH_GRANT_LITERAL];
|
|
747
|
+
const isPinRequired = !!(grantDetails?.tx_code ?? false);
|
|
748
|
+
LOG.warning(`Pin required for issuer ${issuer}: ${isPinRequired}`);
|
|
749
|
+
return {
|
|
750
|
+
txCode: grantDetails?.tx_code,
|
|
751
|
+
isPinRequired
|
|
752
|
+
};
|
|
753
|
+
}
|
|
754
|
+
assertAlphanumericPin(pinMeta, pin) {
|
|
755
|
+
if (pinMeta && pinMeta.isPinRequired) {
|
|
756
|
+
let regex;
|
|
757
|
+
if (pinMeta.txCode) {
|
|
758
|
+
const { input_mode, length } = pinMeta.txCode;
|
|
759
|
+
if (input_mode === "numeric") {
|
|
760
|
+
regex = length ? new RegExp(`^\\d{1,${length}}$`) : /^\d+$/;
|
|
761
|
+
} else if (input_mode === "text") {
|
|
762
|
+
regex = length ? new RegExp(`^[a-zA-Z0-9]{1,${length}}$`) : /^[a-zA-Z0-9]+$/;
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
regex = regex || /^[a-zA-Z0-9]+$|^[A-Za-z0-9-_]+\.[A-Za-z0-9-_]+\.[A-Za-z0-9-_]+$/;
|
|
766
|
+
if (!pin || !regex.test(pin)) {
|
|
767
|
+
LOG.warning(`Pin is not valid. Expected format: ${pinMeta?.txCode?.input_mode || "alphanumeric"}, Length: up to ${pinMeta?.txCode?.length || "any number of"} characters`);
|
|
768
|
+
throw new Error("A valid pin must be present according to the specified transaction code requirements.");
|
|
769
|
+
}
|
|
770
|
+
} else if (pin) {
|
|
771
|
+
LOG.warning("Pin set, whilst not required");
|
|
772
|
+
throw new Error("Cannot set a pin when the pin is not required.");
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
assertNonEmptyPreAuthorizedCode(accessTokenRequest) {
|
|
776
|
+
if (!accessTokenRequest[import_oid4vci_common9.PRE_AUTH_CODE_LITERAL]) {
|
|
777
|
+
LOG.warning(`No pre-authorized code present, whilst it is required`, accessTokenRequest);
|
|
778
|
+
throw new Error("Pre-authorization must be proven by presenting the pre-authorized code. Code must be present.");
|
|
779
|
+
}
|
|
780
|
+
}
|
|
781
|
+
assertNonEmptyCodeVerifier(accessTokenRequest) {
|
|
782
|
+
if (!accessTokenRequest.code_verifier) {
|
|
783
|
+
LOG.warning("No code_verifier present, whilst it is required", accessTokenRequest);
|
|
784
|
+
throw new Error("Authorization flow requires the code_verifier to be present");
|
|
785
|
+
}
|
|
786
|
+
}
|
|
787
|
+
assertNonEmptyCode(accessTokenRequest) {
|
|
788
|
+
if (!accessTokenRequest.code) {
|
|
789
|
+
LOG.warning("No code present, whilst it is required");
|
|
790
|
+
throw new Error("Authorization flow requires the code to be present");
|
|
791
|
+
}
|
|
792
|
+
}
|
|
793
|
+
validate(accessTokenRequest, pinMeta) {
|
|
794
|
+
if (accessTokenRequest.grant_type === import_oid4vci_common9.GrantTypes.PRE_AUTHORIZED_CODE) {
|
|
795
|
+
this.assertPreAuthorizedGrantType(accessTokenRequest.grant_type);
|
|
796
|
+
this.assertNonEmptyPreAuthorizedCode(accessTokenRequest);
|
|
797
|
+
this.assertAlphanumericPin(pinMeta, accessTokenRequest.tx_code ?? accessTokenRequest.user_pin);
|
|
798
|
+
} else if (accessTokenRequest.grant_type === import_oid4vci_common9.GrantTypes.AUTHORIZATION_CODE) {
|
|
799
|
+
this.assertAuthorizationGrantType(accessTokenRequest.grant_type);
|
|
800
|
+
this.assertNonEmptyCodeVerifier(accessTokenRequest);
|
|
801
|
+
this.assertNonEmptyCode(accessTokenRequest);
|
|
802
|
+
} else {
|
|
803
|
+
this.throwNotSupportedFlow();
|
|
804
|
+
}
|
|
805
|
+
}
|
|
806
|
+
async sendAuthCode(requestTokenURL, accessTokenRequest, opts) {
|
|
807
|
+
return await (0, import_oid4vci_common9.formPost)(requestTokenURL, (0, import_oid4vci_common9.convertJsonToURI)(accessTokenRequest, {
|
|
808
|
+
mode: import_oid4vci_common9.JsonURIMode.X_FORM_WWW_URLENCODED
|
|
809
|
+
}), {
|
|
810
|
+
customHeaders: opts?.headers ? opts.headers : void 0
|
|
811
|
+
});
|
|
812
|
+
}
|
|
813
|
+
static determineTokenURL({ asOpts, issuerOpts, metadata }) {
|
|
814
|
+
if (!asOpts && !metadata?.token_endpoint && !issuerOpts) {
|
|
815
|
+
throw new Error("Cannot determine token URL if no issuer, metadata and no Authorization Server values are present");
|
|
816
|
+
}
|
|
817
|
+
let url;
|
|
818
|
+
if (asOpts && asOpts.as) {
|
|
819
|
+
url = this.creatTokenURLFromURL(asOpts.as, asOpts?.allowInsecureEndpoints, asOpts.tokenEndpoint);
|
|
820
|
+
} else if (metadata?.token_endpoint) {
|
|
821
|
+
url = metadata.token_endpoint;
|
|
822
|
+
} else {
|
|
823
|
+
if (!issuerOpts?.issuer) {
|
|
824
|
+
throw Error("Either authorization server options, a token endpoint or issuer options are required at this point");
|
|
825
|
+
}
|
|
826
|
+
url = this.creatTokenURLFromURL(issuerOpts.issuer, asOpts?.allowInsecureEndpoints, issuerOpts.tokenEndpoint);
|
|
827
|
+
}
|
|
828
|
+
if (!url || !import_ssi_types2.ObjectUtils.isString(url)) {
|
|
829
|
+
throw new Error("No authorization server token URL present. Cannot acquire access token");
|
|
830
|
+
}
|
|
831
|
+
LOG.debug(`Token endpoint determined to be ${url}`);
|
|
832
|
+
return url;
|
|
833
|
+
}
|
|
834
|
+
static creatTokenURLFromURL(url, allowInsecureEndpoints, tokenEndpoint) {
|
|
835
|
+
if (allowInsecureEndpoints !== true && url.startsWith("http:")) {
|
|
836
|
+
throw Error(`Unprotected token endpoints are not allowed ${url}. Use the 'allowInsecureEndpoints' param if you really need this for dev/testing!`);
|
|
837
|
+
}
|
|
838
|
+
const hostname = url.replace(/https?:\/\//, "").replace(/\/$/, "");
|
|
839
|
+
const endpoint = tokenEndpoint ? tokenEndpoint.startsWith("/") ? tokenEndpoint : tokenEndpoint.substring(1) : "/token";
|
|
840
|
+
const scheme = url.split("://")[0];
|
|
841
|
+
return `${scheme ? scheme + "://" : "https://"}${hostname}${endpoint}`;
|
|
842
|
+
}
|
|
843
|
+
throwNotSupportedFlow() {
|
|
844
|
+
LOG.warning(`Only pre-authorized or authorization code flows supported.`);
|
|
845
|
+
throw new Error("Only pre-authorized-code or authorization code flows are supported");
|
|
846
|
+
}
|
|
847
|
+
};
|
|
848
|
+
|
|
849
|
+
// lib/AccessTokenClientV1_0_11.ts
|
|
850
|
+
var import_oid4vc_common4 = require("@sphereon/oid4vc-common");
|
|
851
|
+
var import_oid4vci_common10 = require("@sphereon/oid4vci-common");
|
|
852
|
+
var import_ssi_types3 = require("@sphereon/ssi-types");
|
|
853
|
+
var import_debug3 = __toESM(require("debug"), 1);
|
|
854
|
+
var debug3 = (0, import_debug3.default)("sphereon:oid4vci:token");
|
|
855
|
+
var AccessTokenClientV1_0_11 = class _AccessTokenClientV1_0_11 {
|
|
856
|
+
static {
|
|
857
|
+
__name(this, "AccessTokenClientV1_0_11");
|
|
858
|
+
}
|
|
859
|
+
async acquireAccessToken(opts) {
|
|
860
|
+
const { asOpts, pin, codeVerifier, code, redirectUri, metadata, createDPoPOpts } = opts;
|
|
861
|
+
const credentialOffer = opts.credentialOffer ? await (0, import_oid4vci_common10.assertedUniformCredentialOffer)(opts.credentialOffer) : void 0;
|
|
862
|
+
const isPinRequired = credentialOffer && this.isPinRequiredValue(credentialOffer.credential_offer);
|
|
863
|
+
const issuer = opts.credentialIssuer ?? (credentialOffer ? (0, import_oid4vci_common10.getIssuerFromCredentialOfferPayload)(credentialOffer.credential_offer) : metadata?.issuer);
|
|
864
|
+
if (!issuer) {
|
|
865
|
+
throw Error("Issuer required at this point");
|
|
866
|
+
}
|
|
867
|
+
const issuerOpts = {
|
|
868
|
+
issuer
|
|
869
|
+
};
|
|
870
|
+
return await this.acquireAccessTokenUsingRequest({
|
|
871
|
+
accessTokenRequest: await this.createAccessTokenRequest({
|
|
872
|
+
credentialOffer,
|
|
873
|
+
asOpts,
|
|
874
|
+
codeVerifier,
|
|
875
|
+
code,
|
|
876
|
+
redirectUri,
|
|
877
|
+
pin,
|
|
878
|
+
credentialIssuer: issuer,
|
|
879
|
+
metadata,
|
|
880
|
+
additionalParams: opts.additionalParams,
|
|
881
|
+
pinMetadata: opts.pinMetadata
|
|
882
|
+
}),
|
|
883
|
+
isPinRequired,
|
|
884
|
+
metadata,
|
|
885
|
+
asOpts,
|
|
886
|
+
issuerOpts,
|
|
887
|
+
createDPoPOpts
|
|
888
|
+
});
|
|
889
|
+
}
|
|
890
|
+
async acquireAccessTokenUsingRequest({ accessTokenRequest, isPinRequired, metadata, asOpts, createDPoPOpts, issuerOpts }) {
|
|
891
|
+
this.validate(accessTokenRequest, isPinRequired);
|
|
892
|
+
const requestTokenURL = _AccessTokenClientV1_0_11.determineTokenURL({
|
|
893
|
+
asOpts,
|
|
894
|
+
issuerOpts,
|
|
895
|
+
metadata: metadata ? metadata : issuerOpts?.fetchMetadata ? await MetadataClientV1_0_13.retrieveAllMetadata(issuerOpts.issuer, {
|
|
896
|
+
errorOnNotFound: false
|
|
897
|
+
}) : void 0
|
|
898
|
+
});
|
|
899
|
+
const useDpop = createDPoPOpts?.dPoPSigningAlgValuesSupported && createDPoPOpts.dPoPSigningAlgValuesSupported.length > 0;
|
|
900
|
+
let dPoP = useDpop ? await (0, import_oid4vc_common4.createDPoP)((0, import_oid4vc_common4.getCreateDPoPOptions)(createDPoPOpts, requestTokenURL)) : void 0;
|
|
901
|
+
let response = await this.sendAuthCode(requestTokenURL, accessTokenRequest, dPoP ? {
|
|
902
|
+
headers: {
|
|
903
|
+
dpop: dPoP
|
|
904
|
+
}
|
|
905
|
+
} : void 0);
|
|
906
|
+
let nextDPoPNonce = createDPoPOpts?.jwtPayloadProps.nonce;
|
|
907
|
+
const retryWithNonce = shouldRetryTokenRequestWithDPoPNonce(response);
|
|
908
|
+
if (retryWithNonce.ok && createDPoPOpts) {
|
|
909
|
+
createDPoPOpts.jwtPayloadProps.nonce = retryWithNonce.dpopNonce;
|
|
910
|
+
dPoP = await (0, import_oid4vc_common4.createDPoP)((0, import_oid4vc_common4.getCreateDPoPOptions)(createDPoPOpts, requestTokenURL));
|
|
911
|
+
response = await this.sendAuthCode(requestTokenURL, accessTokenRequest, dPoP ? {
|
|
912
|
+
headers: {
|
|
913
|
+
dpop: dPoP
|
|
914
|
+
}
|
|
915
|
+
} : void 0);
|
|
916
|
+
const successDPoPNonce = response.origResponse.headers.get("DPoP-Nonce");
|
|
917
|
+
nextDPoPNonce = successDPoPNonce ?? retryWithNonce.dpopNonce;
|
|
918
|
+
}
|
|
919
|
+
if (response.successBody && createDPoPOpts && response.successBody.token_type !== "DPoP") {
|
|
920
|
+
throw new Error("Invalid token type returned. Expected DPoP. Received: " + response.successBody.token_type);
|
|
921
|
+
}
|
|
922
|
+
return {
|
|
923
|
+
...response,
|
|
924
|
+
...nextDPoPNonce && {
|
|
925
|
+
params: {
|
|
926
|
+
dpop: {
|
|
927
|
+
dpopNonce: nextDPoPNonce
|
|
928
|
+
}
|
|
929
|
+
}
|
|
930
|
+
}
|
|
931
|
+
};
|
|
932
|
+
}
|
|
933
|
+
async createAccessTokenRequest(opts) {
|
|
934
|
+
const { asOpts, pin, codeVerifier, code, redirectUri } = opts;
|
|
935
|
+
const credentialOfferRequest = opts.credentialOffer ? await (0, import_oid4vci_common10.toUniformCredentialOfferRequest)(opts.credentialOffer) : void 0;
|
|
936
|
+
const request = {
|
|
937
|
+
...opts.additionalParams
|
|
938
|
+
};
|
|
939
|
+
const credentialIssuer = opts.credentialIssuer ?? credentialOfferRequest?.credential_offer?.credential_issuer ?? opts.metadata?.issuer;
|
|
940
|
+
if (asOpts?.clientOpts?.clientId) {
|
|
941
|
+
request.client_id = asOpts.clientOpts.clientId;
|
|
942
|
+
}
|
|
943
|
+
await createJwtBearerClientAssertion(request, {
|
|
944
|
+
...opts,
|
|
945
|
+
version: import_oid4vci_common10.OpenId4VCIVersion.VER_1_0_11,
|
|
946
|
+
credentialIssuer
|
|
947
|
+
});
|
|
948
|
+
if (!credentialOfferRequest || credentialOfferRequest.supportedFlows.includes(import_oid4vci_common10.AuthzFlowType.AUTHORIZATION_CODE_FLOW)) {
|
|
949
|
+
request.grant_type = import_oid4vci_common10.GrantTypes.AUTHORIZATION_CODE;
|
|
950
|
+
request.code = code;
|
|
951
|
+
request.redirect_uri = redirectUri;
|
|
952
|
+
if (codeVerifier) {
|
|
953
|
+
request.code_verifier = codeVerifier;
|
|
954
|
+
}
|
|
955
|
+
return request;
|
|
956
|
+
}
|
|
957
|
+
if (credentialOfferRequest?.supportedFlows.includes(import_oid4vci_common10.AuthzFlowType.PRE_AUTHORIZED_CODE_FLOW)) {
|
|
958
|
+
this.assertNumericPin(this.isPinRequiredValue(credentialOfferRequest.credential_offer), pin);
|
|
959
|
+
request.user_pin = pin;
|
|
960
|
+
request.grant_type = import_oid4vci_common10.GrantTypes.PRE_AUTHORIZED_CODE;
|
|
961
|
+
request[import_oid4vci_common10.PRE_AUTH_CODE_LITERAL] = credentialOfferRequest?.credential_offer.grants?.[import_oid4vci_common10.PRE_AUTH_GRANT_LITERAL]?.[import_oid4vci_common10.PRE_AUTH_CODE_LITERAL];
|
|
962
|
+
return request;
|
|
963
|
+
}
|
|
964
|
+
throw new Error("Credential offer request does not follow neither pre-authorized code nor authorization code flow requirements.");
|
|
965
|
+
}
|
|
966
|
+
assertPreAuthorizedGrantType(grantType) {
|
|
967
|
+
if (import_oid4vci_common10.GrantTypes.PRE_AUTHORIZED_CODE !== grantType) {
|
|
968
|
+
throw new Error("grant type must be PRE_AUTH_GRANT_LITERAL");
|
|
969
|
+
}
|
|
970
|
+
}
|
|
971
|
+
assertAuthorizationGrantType(grantType) {
|
|
972
|
+
if (import_oid4vci_common10.GrantTypes.AUTHORIZATION_CODE !== grantType) {
|
|
973
|
+
throw new Error("grant type must be 'authorization_code'");
|
|
974
|
+
}
|
|
975
|
+
}
|
|
976
|
+
isPinRequiredValue(requestPayload) {
|
|
977
|
+
let isPinRequired = false;
|
|
978
|
+
if (!requestPayload) {
|
|
979
|
+
throw new Error(import_oid4vci_common10.TokenErrorResponse.invalid_request);
|
|
980
|
+
}
|
|
981
|
+
const issuer = (0, import_oid4vci_common10.getIssuerFromCredentialOfferPayload)(requestPayload);
|
|
982
|
+
if (requestPayload.grants?.[import_oid4vci_common10.PRE_AUTH_GRANT_LITERAL]) {
|
|
983
|
+
isPinRequired = requestPayload.grants[import_oid4vci_common10.PRE_AUTH_GRANT_LITERAL]?.user_pin_required ?? false;
|
|
984
|
+
}
|
|
985
|
+
debug3(`Pin required for issuer ${issuer}: ${isPinRequired}`);
|
|
986
|
+
return isPinRequired;
|
|
987
|
+
}
|
|
988
|
+
assertNumericPin(isPinRequired, pin) {
|
|
989
|
+
if (isPinRequired) {
|
|
990
|
+
if (!pin || !/^\d{1,8}$/.test(pin)) {
|
|
991
|
+
debug3(`Pin is not 1 to 8 digits long`);
|
|
992
|
+
throw new Error("A valid pin consisting of maximal 8 numeric characters must be present.");
|
|
993
|
+
}
|
|
994
|
+
} else if (pin) {
|
|
995
|
+
debug3(`Pin set, whilst not required`);
|
|
996
|
+
throw new Error("Cannot set a pin, when the pin is not required.");
|
|
997
|
+
}
|
|
998
|
+
}
|
|
999
|
+
assertNonEmptyPreAuthorizedCode(accessTokenRequest) {
|
|
1000
|
+
if (!accessTokenRequest[import_oid4vci_common10.PRE_AUTH_CODE_LITERAL]) {
|
|
1001
|
+
debug3(`No pre-authorized code present, whilst it is required`);
|
|
1002
|
+
throw new Error("Pre-authorization must be proven by presenting the pre-authorized code. Code must be present.");
|
|
1003
|
+
}
|
|
1004
|
+
}
|
|
1005
|
+
assertNonEmptyCodeVerifier(accessTokenRequest) {
|
|
1006
|
+
if (!accessTokenRequest.code_verifier) {
|
|
1007
|
+
debug3("No code_verifier present, whilst it is required");
|
|
1008
|
+
throw new Error("Authorization flow requires the code_verifier to be present");
|
|
1009
|
+
}
|
|
1010
|
+
}
|
|
1011
|
+
assertNonEmptyCode(accessTokenRequest) {
|
|
1012
|
+
if (!accessTokenRequest.code) {
|
|
1013
|
+
debug3("No code present, whilst it is required");
|
|
1014
|
+
throw new Error("Authorization flow requires the code to be present");
|
|
1015
|
+
}
|
|
1016
|
+
}
|
|
1017
|
+
validate(accessTokenRequest, isPinRequired) {
|
|
1018
|
+
if (accessTokenRequest.grant_type === import_oid4vci_common10.GrantTypes.PRE_AUTHORIZED_CODE) {
|
|
1019
|
+
this.assertPreAuthorizedGrantType(accessTokenRequest.grant_type);
|
|
1020
|
+
this.assertNonEmptyPreAuthorizedCode(accessTokenRequest);
|
|
1021
|
+
this.assertNumericPin(isPinRequired, accessTokenRequest.user_pin);
|
|
1022
|
+
} else if (accessTokenRequest.grant_type === import_oid4vci_common10.GrantTypes.AUTHORIZATION_CODE) {
|
|
1023
|
+
this.assertAuthorizationGrantType(accessTokenRequest.grant_type);
|
|
1024
|
+
this.assertNonEmptyCodeVerifier(accessTokenRequest);
|
|
1025
|
+
this.assertNonEmptyCode(accessTokenRequest);
|
|
1026
|
+
} else {
|
|
1027
|
+
this.throwNotSupportedFlow();
|
|
1028
|
+
}
|
|
1029
|
+
}
|
|
1030
|
+
async sendAuthCode(requestTokenURL, accessTokenRequest, opts) {
|
|
1031
|
+
return await (0, import_oid4vci_common10.formPost)(requestTokenURL, (0, import_oid4vci_common10.convertJsonToURI)(accessTokenRequest, {
|
|
1032
|
+
mode: import_oid4vci_common10.JsonURIMode.X_FORM_WWW_URLENCODED
|
|
1033
|
+
}), {
|
|
1034
|
+
customHeaders: opts?.headers ? opts.headers : void 0
|
|
1035
|
+
});
|
|
1036
|
+
}
|
|
1037
|
+
static determineTokenURL({ asOpts, issuerOpts, metadata }) {
|
|
1038
|
+
if (!asOpts && !metadata?.token_endpoint && !issuerOpts) {
|
|
1039
|
+
throw new Error("Cannot determine token URL if no issuer, metadata and no Authorization Server values are present");
|
|
1040
|
+
}
|
|
1041
|
+
let url;
|
|
1042
|
+
if (asOpts && asOpts.as) {
|
|
1043
|
+
url = this.creatTokenURLFromURL(asOpts.as, asOpts?.allowInsecureEndpoints, asOpts.tokenEndpoint);
|
|
1044
|
+
} else if (metadata?.token_endpoint) {
|
|
1045
|
+
url = metadata.token_endpoint;
|
|
1046
|
+
} else {
|
|
1047
|
+
if (!issuerOpts?.issuer) {
|
|
1048
|
+
throw Error("Either authorization server options, a token endpoint or issuer options are required at this point");
|
|
1049
|
+
}
|
|
1050
|
+
url = this.creatTokenURLFromURL(issuerOpts.issuer, asOpts?.allowInsecureEndpoints, issuerOpts.tokenEndpoint);
|
|
1051
|
+
}
|
|
1052
|
+
if (!url || !import_ssi_types3.ObjectUtils.isString(url)) {
|
|
1053
|
+
throw new Error("No authorization server token URL present. Cannot acquire access token");
|
|
1054
|
+
}
|
|
1055
|
+
debug3(`Token endpoint determined to be ${url}`);
|
|
1056
|
+
return url;
|
|
1057
|
+
}
|
|
1058
|
+
static creatTokenURLFromURL(url, allowInsecureEndpoints, tokenEndpoint) {
|
|
1059
|
+
if (allowInsecureEndpoints !== true && url.startsWith("http:")) {
|
|
1060
|
+
throw Error(`Unprotected token endpoints are not allowed ${url}. Use the 'allowInsecureEndpoints' param if you really need this for dev/testing!`);
|
|
1061
|
+
}
|
|
1062
|
+
const hostname = url.replace(/https?:\/\//, "").replace(/\/$/, "");
|
|
1063
|
+
const endpoint = tokenEndpoint ? tokenEndpoint.startsWith("/") ? tokenEndpoint : tokenEndpoint.substring(1) : "/token";
|
|
1064
|
+
const scheme = url.split("://")[0];
|
|
1065
|
+
return `${scheme ? scheme + "://" : "https://"}${hostname}${endpoint}`;
|
|
1066
|
+
}
|
|
1067
|
+
throwNotSupportedFlow() {
|
|
1068
|
+
debug3(`Only pre-authorized or authorization code flows supported.`);
|
|
1069
|
+
throw new Error("Only pre-authorized-code or authorization code flows are supported");
|
|
1070
|
+
}
|
|
1071
|
+
};
|
|
1072
|
+
|
|
1073
|
+
// lib/AuthorizationCodeClient.ts
|
|
1074
|
+
var import_oid4vci_common13 = require("@sphereon/oid4vci-common");
|
|
1075
|
+
var import_debug6 = __toESM(require("debug"), 1);
|
|
1076
|
+
|
|
1077
|
+
// lib/MetadataClient.ts
|
|
1078
|
+
var import_oid4vci_common12 = require("@sphereon/oid4vci-common");
|
|
1079
|
+
var import_debug5 = __toESM(require("debug"), 1);
|
|
1080
|
+
|
|
1081
|
+
// lib/MetadataClientV1_0_11.ts
|
|
1082
|
+
var import_oid4vci_common11 = require("@sphereon/oid4vci-common");
|
|
1083
|
+
var import_debug4 = __toESM(require("debug"), 1);
|
|
1084
|
+
var debug4 = (0, import_debug4.default)("sphereon:oid4vci:metadata");
|
|
1085
|
+
var MetadataClientV1_0_11 = class _MetadataClientV1_0_11 {
|
|
1086
|
+
static {
|
|
1087
|
+
__name(this, "MetadataClientV1_0_11");
|
|
1088
|
+
}
|
|
1089
|
+
/**
|
|
1090
|
+
* Retrieve metadata using the Initiation obtained from a previous step
|
|
1091
|
+
*
|
|
1092
|
+
* @param credentialOffer
|
|
1093
|
+
*/
|
|
1094
|
+
static async retrieveAllMetadataFromCredentialOffer(credentialOffer) {
|
|
1095
|
+
return _MetadataClientV1_0_11.retrieveAllMetadataFromCredentialOfferRequest(credentialOffer.credential_offer);
|
|
1096
|
+
}
|
|
1097
|
+
/**
|
|
1098
|
+
* Retrieve the metada using the initiation request obtained from a previous step
|
|
1099
|
+
* @param request
|
|
1100
|
+
*/
|
|
1101
|
+
static async retrieveAllMetadataFromCredentialOfferRequest(request) {
|
|
1102
|
+
const issuer = (0, import_oid4vci_common11.getIssuerFromCredentialOfferPayload)(request);
|
|
1103
|
+
if (issuer) {
|
|
1104
|
+
return _MetadataClientV1_0_11.retrieveAllMetadata(issuer);
|
|
1105
|
+
}
|
|
1106
|
+
throw new Error("can't retrieve metadata from CredentialOfferRequest. No issuer field is present");
|
|
1107
|
+
}
|
|
1108
|
+
/**
|
|
1109
|
+
* Retrieve all metadata from an issuer
|
|
1110
|
+
* @param issuer The issuer URL
|
|
1111
|
+
* @param opts
|
|
1112
|
+
*/
|
|
1113
|
+
static async retrieveAllMetadata(issuer, opts) {
|
|
1114
|
+
let token_endpoint;
|
|
1115
|
+
let credential_endpoint;
|
|
1116
|
+
let deferred_credential_endpoint;
|
|
1117
|
+
let authorization_endpoint;
|
|
1118
|
+
let authorization_challenge_endpoint;
|
|
1119
|
+
let authorizationServerType = "OID4VCI";
|
|
1120
|
+
let authorization_server = issuer;
|
|
1121
|
+
const oid4vciResponse = await _MetadataClientV1_0_11.retrieveOpenID4VCIServerMetadata(issuer, {
|
|
1122
|
+
errorOnNotFound: false
|
|
1123
|
+
});
|
|
1124
|
+
let credentialIssuerMetadata = oid4vciResponse?.successBody;
|
|
1125
|
+
if (credentialIssuerMetadata) {
|
|
1126
|
+
debug4(`Issuer ${issuer} OID4VCI well-known server metadata\r
|
|
1127
|
+
${JSON.stringify(credentialIssuerMetadata)}`);
|
|
1128
|
+
credential_endpoint = credentialIssuerMetadata.credential_endpoint;
|
|
1129
|
+
deferred_credential_endpoint = credentialIssuerMetadata.deferred_credential_endpoint;
|
|
1130
|
+
if (credentialIssuerMetadata.token_endpoint) {
|
|
1131
|
+
token_endpoint = credentialIssuerMetadata.token_endpoint;
|
|
1132
|
+
}
|
|
1133
|
+
authorization_challenge_endpoint = credentialIssuerMetadata.authorization_challenge_endpoint;
|
|
1134
|
+
if (credentialIssuerMetadata.authorization_server) {
|
|
1135
|
+
authorization_server = credentialIssuerMetadata.authorization_server;
|
|
1136
|
+
}
|
|
1137
|
+
if (credentialIssuerMetadata.authorization_endpoint) {
|
|
1138
|
+
authorization_endpoint = credentialIssuerMetadata.authorization_endpoint;
|
|
1139
|
+
}
|
|
1140
|
+
}
|
|
1141
|
+
let response = await retrieveWellknown(authorization_server, import_oid4vci_common11.WellKnownEndpoints.OPENID_CONFIGURATION, {
|
|
1142
|
+
errorOnNotFound: false
|
|
1143
|
+
});
|
|
1144
|
+
let authMetadata = response.successBody;
|
|
1145
|
+
if (authMetadata) {
|
|
1146
|
+
debug4(`Issuer ${issuer} has OpenID Connect Server metadata in well-known location`);
|
|
1147
|
+
authorizationServerType = "OIDC";
|
|
1148
|
+
} else {
|
|
1149
|
+
response = await retrieveWellknown(authorization_server, import_oid4vci_common11.WellKnownEndpoints.OAUTH_AS, {
|
|
1150
|
+
errorOnNotFound: false
|
|
1151
|
+
});
|
|
1152
|
+
authMetadata = response.successBody;
|
|
1153
|
+
}
|
|
1154
|
+
if (!authMetadata) {
|
|
1155
|
+
if (issuer !== authorization_server) {
|
|
1156
|
+
throw Error(`Issuer ${issuer} provided a separate authorization server ${authorization_server}, but that server did not provide metadata`);
|
|
1157
|
+
}
|
|
1158
|
+
} else {
|
|
1159
|
+
if (!authorizationServerType) {
|
|
1160
|
+
authorizationServerType = "OAuth 2.0";
|
|
1161
|
+
}
|
|
1162
|
+
debug4(`Issuer ${issuer} has ${authorizationServerType} Server metadata in well-known location`);
|
|
1163
|
+
if (!authMetadata.authorization_endpoint) {
|
|
1164
|
+
console.warn(`Issuer ${issuer} of type ${authorizationServerType} has no authorization_endpoint! Will use ${authorization_endpoint}. This only works for pre-authorized flows`);
|
|
1165
|
+
} else if (authorization_endpoint && authMetadata.authorization_endpoint !== authorization_endpoint) {
|
|
1166
|
+
throw Error(`Credential issuer has a different authorization_endpoint (${authorization_endpoint}) from the Authorization Server (${authMetadata.authorization_endpoint})`);
|
|
1167
|
+
}
|
|
1168
|
+
authorization_endpoint = authMetadata.authorization_endpoint;
|
|
1169
|
+
if (authorization_challenge_endpoint && authMetadata.authorization_challenge_endpoint !== authorization_challenge_endpoint) {
|
|
1170
|
+
throw Error(`Credential issuer has a different authorization_challenge_endpoint (${authorization_challenge_endpoint}) from the Authorization Server (${authMetadata.authorization_challenge_endpoint})`);
|
|
1171
|
+
}
|
|
1172
|
+
authorization_challenge_endpoint = authMetadata.authorization_challenge_endpoint;
|
|
1173
|
+
if (!authMetadata.token_endpoint) {
|
|
1174
|
+
throw Error(`Authorization Server ${authorization_server} did not provide a token_endpoint`);
|
|
1175
|
+
} else if (token_endpoint && authMetadata.token_endpoint !== token_endpoint) {
|
|
1176
|
+
throw Error(`Credential issuer has a different token_endpoint (${token_endpoint}) from the Authorization Server (${authMetadata.token_endpoint})`);
|
|
1177
|
+
}
|
|
1178
|
+
token_endpoint = authMetadata.token_endpoint;
|
|
1179
|
+
if (authMetadata.credential_endpoint) {
|
|
1180
|
+
if (credential_endpoint && authMetadata.credential_endpoint !== credential_endpoint) {
|
|
1181
|
+
debug4(`Credential issuer has a different credential_endpoint (${credential_endpoint}) from the Authorization Server (${authMetadata.credential_endpoint}). Will use the issuer value`);
|
|
1182
|
+
} else {
|
|
1183
|
+
credential_endpoint = authMetadata.credential_endpoint;
|
|
1184
|
+
}
|
|
1185
|
+
}
|
|
1186
|
+
if (authMetadata.deferred_credential_endpoint) {
|
|
1187
|
+
if (deferred_credential_endpoint && authMetadata.deferred_credential_endpoint !== deferred_credential_endpoint) {
|
|
1188
|
+
debug4(`Credential issuer has a different deferred_credential_endpoint (${deferred_credential_endpoint}) from the Authorization Server (${authMetadata.deferred_credential_endpoint}). Will use the issuer value`);
|
|
1189
|
+
} else {
|
|
1190
|
+
deferred_credential_endpoint = authMetadata.deferred_credential_endpoint;
|
|
1191
|
+
}
|
|
1192
|
+
}
|
|
1193
|
+
}
|
|
1194
|
+
if (!authorization_endpoint) {
|
|
1195
|
+
debug4(`Issuer ${issuer} does not expose authorization_endpoint, so only pre-auth will be supported`);
|
|
1196
|
+
}
|
|
1197
|
+
if (!token_endpoint) {
|
|
1198
|
+
debug4(`Issuer ${issuer} does not have a token_endpoint listed in well-known locations!`);
|
|
1199
|
+
if (opts?.errorOnNotFound) {
|
|
1200
|
+
throw Error(`Could not deduce the token_endpoint for ${issuer}`);
|
|
1201
|
+
} else {
|
|
1202
|
+
token_endpoint = `${issuer}${issuer.endsWith("/") ? "token" : "/token"}`;
|
|
1203
|
+
}
|
|
1204
|
+
}
|
|
1205
|
+
if (!credential_endpoint) {
|
|
1206
|
+
debug4(`Issuer ${issuer} does not have a credential_endpoint listed in well-known locations!`);
|
|
1207
|
+
if (opts?.errorOnNotFound) {
|
|
1208
|
+
throw Error(`Could not deduce the credential endpoint for ${issuer}`);
|
|
1209
|
+
} else {
|
|
1210
|
+
credential_endpoint = `${issuer}${issuer.endsWith("/") ? "credential" : "/credential"}`;
|
|
1211
|
+
}
|
|
1212
|
+
}
|
|
1213
|
+
if (!credentialIssuerMetadata && authMetadata) {
|
|
1214
|
+
credentialIssuerMetadata = authMetadata;
|
|
1215
|
+
}
|
|
1216
|
+
debug4(`Issuer ${issuer} token endpoint ${token_endpoint}, credential endpoint ${credential_endpoint}`);
|
|
1217
|
+
return {
|
|
1218
|
+
issuer,
|
|
1219
|
+
token_endpoint,
|
|
1220
|
+
credential_endpoint,
|
|
1221
|
+
deferred_credential_endpoint,
|
|
1222
|
+
authorization_server,
|
|
1223
|
+
authorization_endpoint,
|
|
1224
|
+
authorization_challenge_endpoint,
|
|
1225
|
+
authorizationServerType,
|
|
1226
|
+
credentialIssuerMetadata,
|
|
1227
|
+
authorizationServerMetadata: authMetadata
|
|
1228
|
+
};
|
|
1229
|
+
}
|
|
1230
|
+
/**
|
|
1231
|
+
* Retrieve only the OID4VCI metadata for the issuer. So no OIDC/OAuth2 metadata
|
|
1232
|
+
*
|
|
1233
|
+
* @param issuerHost The issuer hostname
|
|
1234
|
+
*/
|
|
1235
|
+
static async retrieveOpenID4VCIServerMetadata(issuerHost, opts) {
|
|
1236
|
+
return retrieveWellknown(issuerHost, import_oid4vci_common11.WellKnownEndpoints.OPENID4VCI_ISSUER, {
|
|
1237
|
+
errorOnNotFound: opts?.errorOnNotFound === void 0 ? true : opts.errorOnNotFound
|
|
1238
|
+
});
|
|
1239
|
+
}
|
|
1240
|
+
};
|
|
1241
|
+
|
|
1242
|
+
// lib/MetadataClient.ts
|
|
1243
|
+
var debug5 = (0, import_debug5.default)("sphereon:oid4vci:metadata");
|
|
1244
|
+
var MetadataClient = class _MetadataClient {
|
|
1245
|
+
static {
|
|
1246
|
+
__name(this, "MetadataClient");
|
|
1247
|
+
}
|
|
1248
|
+
/**
|
|
1249
|
+
* Retrieve metadata using the Initiation obtained from a previous step
|
|
1250
|
+
*
|
|
1251
|
+
* @param credentialOffer
|
|
1252
|
+
*/
|
|
1253
|
+
static async retrieveAllMetadataFromCredentialOffer(credentialOffer) {
|
|
1254
|
+
if ((0, import_oid4vci_common12.determineSpecVersionFromOffer)(credentialOffer.credential_offer) >= import_oid4vci_common12.OpenId4VCIVersion.VER_1_0_13) {
|
|
1255
|
+
return await MetadataClientV1_0_13.retrieveAllMetadataFromCredentialOffer(credentialOffer);
|
|
1256
|
+
} else {
|
|
1257
|
+
return await MetadataClientV1_0_11.retrieveAllMetadataFromCredentialOffer(credentialOffer);
|
|
1258
|
+
}
|
|
1259
|
+
}
|
|
1260
|
+
/**
|
|
1261
|
+
* Retrieve the metada using the initiation request obtained from a previous step
|
|
1262
|
+
* @param request
|
|
1263
|
+
*/
|
|
1264
|
+
static async retrieveAllMetadataFromCredentialOfferRequest(request) {
|
|
1265
|
+
const issuer = (0, import_oid4vci_common12.getIssuerFromCredentialOfferPayload)(request);
|
|
1266
|
+
if (issuer) {
|
|
1267
|
+
if ((0, import_oid4vci_common12.determineSpecVersionFromOffer)(request) >= import_oid4vci_common12.OpenId4VCIVersion.VER_1_0_13) {
|
|
1268
|
+
return MetadataClientV1_0_13.retrieveAllMetadataFromCredentialOfferRequest(request);
|
|
1269
|
+
} else {
|
|
1270
|
+
return MetadataClientV1_0_11.retrieveAllMetadataFromCredentialOfferRequest(request);
|
|
1271
|
+
}
|
|
1272
|
+
}
|
|
1273
|
+
throw new Error("can't retrieve metadata from CredentialOfferRequest. No issuer field is present");
|
|
1274
|
+
}
|
|
1275
|
+
/**
|
|
1276
|
+
* Retrieve all metadata from an issuer
|
|
1277
|
+
* @param issuer The issuer URL
|
|
1278
|
+
* @param opts
|
|
1279
|
+
*/
|
|
1280
|
+
static async retrieveAllMetadata(issuer, opts) {
|
|
1281
|
+
let token_endpoint;
|
|
1282
|
+
let credential_endpoint;
|
|
1283
|
+
let deferred_credential_endpoint;
|
|
1284
|
+
let authorization_endpoint;
|
|
1285
|
+
let authorization_challenge_endpoint;
|
|
1286
|
+
let authorizationServerType = "OID4VCI";
|
|
1287
|
+
let authorization_servers = [
|
|
1288
|
+
issuer
|
|
1289
|
+
];
|
|
1290
|
+
let authorization_server = void 0;
|
|
1291
|
+
const oid4vciResponse = await _MetadataClient.retrieveOpenID4VCIServerMetadata(issuer, {
|
|
1292
|
+
errorOnNotFound: false
|
|
1293
|
+
});
|
|
1294
|
+
let credentialIssuerMetadata = oid4vciResponse?.successBody;
|
|
1295
|
+
if (credentialIssuerMetadata) {
|
|
1296
|
+
debug5(`Issuer ${issuer} OID4VCI well-known server metadata\r
|
|
1297
|
+
${JSON.stringify(credentialIssuerMetadata)}`);
|
|
1298
|
+
credential_endpoint = credentialIssuerMetadata.credential_endpoint;
|
|
1299
|
+
deferred_credential_endpoint = credentialIssuerMetadata.deferred_credential_endpoint ? credentialIssuerMetadata.deferred_credential_endpoint : void 0;
|
|
1300
|
+
if (credentialIssuerMetadata.token_endpoint) {
|
|
1301
|
+
token_endpoint = credentialIssuerMetadata.token_endpoint;
|
|
1302
|
+
}
|
|
1303
|
+
authorization_challenge_endpoint = credentialIssuerMetadata.authorization_challenge_endpoint;
|
|
1304
|
+
if (credentialIssuerMetadata.authorization_servers) {
|
|
1305
|
+
authorization_servers = credentialIssuerMetadata.authorization_servers;
|
|
1306
|
+
} else if (credentialIssuerMetadata.authorization_server) {
|
|
1307
|
+
authorization_server = credentialIssuerMetadata.authorization_server;
|
|
1308
|
+
authorization_servers = [
|
|
1309
|
+
authorization_server
|
|
1310
|
+
];
|
|
1311
|
+
}
|
|
1312
|
+
}
|
|
1313
|
+
let response = await retrieveWellknown(authorization_servers[0], import_oid4vci_common12.WellKnownEndpoints.OPENID_CONFIGURATION, {
|
|
1314
|
+
errorOnNotFound: false
|
|
1315
|
+
});
|
|
1316
|
+
let authMetadata = response.successBody;
|
|
1317
|
+
if (authMetadata) {
|
|
1318
|
+
debug5(`Issuer ${issuer} has OpenID Connect Server metadata in well-known location`);
|
|
1319
|
+
authorizationServerType = "OIDC";
|
|
1320
|
+
} else {
|
|
1321
|
+
response = await retrieveWellknown(authorization_servers[0], import_oid4vci_common12.WellKnownEndpoints.OAUTH_AS, {
|
|
1322
|
+
errorOnNotFound: false
|
|
1323
|
+
});
|
|
1324
|
+
authMetadata = response.successBody;
|
|
1325
|
+
}
|
|
1326
|
+
if (!authMetadata) {
|
|
1327
|
+
if (!authorization_servers.includes(issuer)) {
|
|
1328
|
+
throw Error(`Issuer ${issuer} provided a separate authorization server ${authorization_servers}, but that server did not provide metadata`);
|
|
1329
|
+
}
|
|
1330
|
+
} else {
|
|
1331
|
+
if (!authorizationServerType) {
|
|
1332
|
+
authorizationServerType = "OAuth 2.0";
|
|
1333
|
+
}
|
|
1334
|
+
debug5(`Issuer ${issuer} has ${authorizationServerType} Server metadata in well-known location`);
|
|
1335
|
+
if (!authMetadata.authorization_endpoint) {
|
|
1336
|
+
console.warn(`Issuer ${issuer} of type ${authorizationServerType} has no authorization_endpoint! Will use ${authorization_endpoint}. This only works for pre-authorized flows`);
|
|
1337
|
+
} else if (authorization_endpoint && authMetadata.authorization_endpoint !== authorization_endpoint) {
|
|
1338
|
+
throw Error(`Credential issuer has a different authorization_endpoint (${authorization_endpoint}) from the Authorization Server (${authMetadata.authorization_endpoint})`);
|
|
1339
|
+
}
|
|
1340
|
+
authorization_endpoint = authMetadata.authorization_endpoint;
|
|
1341
|
+
if (authorization_challenge_endpoint && authMetadata.authorization_challenge_endpoint !== authorization_challenge_endpoint) {
|
|
1342
|
+
throw Error(`Credential issuer has a different authorization_challenge_endpoint (${authorization_challenge_endpoint}) from the Authorization Server (${authMetadata.authorization_challenge_endpoint})`);
|
|
1343
|
+
}
|
|
1344
|
+
authorization_challenge_endpoint = authMetadata.authorization_challenge_endpoint;
|
|
1345
|
+
if (!authMetadata.token_endpoint) {
|
|
1346
|
+
throw Error(`Authorization Server ${authorization_servers} did not provide a token_endpoint`);
|
|
1347
|
+
} else if (token_endpoint && authMetadata.token_endpoint !== token_endpoint) {
|
|
1348
|
+
throw Error(`Credential issuer has a different token_endpoint (${token_endpoint}) from the Authorization Server (${authMetadata.token_endpoint})`);
|
|
1349
|
+
}
|
|
1350
|
+
token_endpoint = authMetadata.token_endpoint;
|
|
1351
|
+
if (authMetadata.credential_endpoint) {
|
|
1352
|
+
if (credential_endpoint && authMetadata.credential_endpoint !== credential_endpoint) {
|
|
1353
|
+
debug5(`Credential issuer has a different credential_endpoint (${credential_endpoint}) from the Authorization Server (${authMetadata.credential_endpoint}). Will use the issuer value`);
|
|
1354
|
+
} else {
|
|
1355
|
+
credential_endpoint = authMetadata.credential_endpoint;
|
|
1356
|
+
}
|
|
1357
|
+
}
|
|
1358
|
+
if (authMetadata.deferred_credential_endpoint) {
|
|
1359
|
+
if (deferred_credential_endpoint && authMetadata.deferred_credential_endpoint !== deferred_credential_endpoint) {
|
|
1360
|
+
debug5(`Credential issuer has a different deferred_credential_endpoint (${deferred_credential_endpoint}) from the Authorization Server (${authMetadata.deferred_credential_endpoint}). Will use the issuer value`);
|
|
1361
|
+
} else {
|
|
1362
|
+
deferred_credential_endpoint = authMetadata.deferred_credential_endpoint;
|
|
1363
|
+
}
|
|
1364
|
+
}
|
|
1365
|
+
}
|
|
1366
|
+
if (!authorization_endpoint) {
|
|
1367
|
+
debug5(`Issuer ${issuer} does not expose authorization_endpoint, so only pre-auth will be supported`);
|
|
1368
|
+
}
|
|
1369
|
+
if (!token_endpoint) {
|
|
1370
|
+
debug5(`Issuer ${issuer} does not have a token_endpoint listed in well-known locations!`);
|
|
1371
|
+
if (opts?.errorOnNotFound) {
|
|
1372
|
+
throw Error(`Could not deduce the token_endpoint for ${issuer}`);
|
|
1373
|
+
} else {
|
|
1374
|
+
token_endpoint = `${issuer}${issuer.endsWith("/") ? "token" : "/token"}`;
|
|
1375
|
+
}
|
|
1376
|
+
}
|
|
1377
|
+
if (!credential_endpoint) {
|
|
1378
|
+
debug5(`Issuer ${issuer} does not have a credential_endpoint listed in well-known locations!`);
|
|
1379
|
+
if (opts?.errorOnNotFound) {
|
|
1380
|
+
throw Error(`Could not deduce the credential endpoint for ${issuer}`);
|
|
1381
|
+
} else {
|
|
1382
|
+
credential_endpoint = `${issuer}${issuer.endsWith("/") ? "credential" : "/credential"}`;
|
|
1383
|
+
}
|
|
1384
|
+
}
|
|
1385
|
+
if (!credentialIssuerMetadata && authMetadata) {
|
|
1386
|
+
credentialIssuerMetadata = authorization_server ? authMetadata : authMetadata;
|
|
1387
|
+
}
|
|
1388
|
+
debug5(`Issuer ${issuer} token endpoint ${token_endpoint}, credential endpoint ${credential_endpoint}`);
|
|
1389
|
+
return {
|
|
1390
|
+
issuer,
|
|
1391
|
+
token_endpoint,
|
|
1392
|
+
credential_endpoint,
|
|
1393
|
+
deferred_credential_endpoint,
|
|
1394
|
+
...authorization_server ? {
|
|
1395
|
+
authorization_server
|
|
1396
|
+
} : {
|
|
1397
|
+
authorization_servers
|
|
1398
|
+
},
|
|
1399
|
+
authorization_endpoint,
|
|
1400
|
+
authorization_challenge_endpoint,
|
|
1401
|
+
authorizationServerType,
|
|
1402
|
+
credentialIssuerMetadata: authorization_server ? credentialIssuerMetadata : credentialIssuerMetadata,
|
|
1403
|
+
authorizationServerMetadata: authMetadata
|
|
1404
|
+
};
|
|
1405
|
+
}
|
|
1406
|
+
/**
|
|
1407
|
+
* Retrieve only the OID4VCI metadata for the issuer. So no OIDC/OAuth2 metadata
|
|
1408
|
+
*
|
|
1409
|
+
* @param issuerHost The issuer hostname
|
|
1410
|
+
* @param opts
|
|
1411
|
+
*/
|
|
1412
|
+
static async retrieveOpenID4VCIServerMetadata(issuerHost, opts) {
|
|
1413
|
+
return retrieveWellknown(issuerHost, import_oid4vci_common12.WellKnownEndpoints.OPENID4VCI_ISSUER, {
|
|
1414
|
+
errorOnNotFound: opts?.errorOnNotFound === void 0 ? true : opts.errorOnNotFound
|
|
1415
|
+
});
|
|
1416
|
+
}
|
|
1417
|
+
};
|
|
1418
|
+
|
|
1419
|
+
// lib/AuthorizationCodeClient.ts
|
|
1420
|
+
var debug6 = (0, import_debug6.default)("sphereon:oid4vci");
|
|
1421
|
+
async function createSignedAuthRequestWhenNeeded(requestObject, opts) {
|
|
1422
|
+
if (opts.requestObjectMode === import_oid4vci_common13.CreateRequestObjectMode.REQUEST_URI) {
|
|
1423
|
+
throw Error(`Request Object Mode ${opts.requestObjectMode} is not supported yet`);
|
|
1424
|
+
} else if (opts.requestObjectMode === import_oid4vci_common13.CreateRequestObjectMode.REQUEST_OBJECT) {
|
|
1425
|
+
if (typeof opts.signCallbacks?.signCallback !== "function") {
|
|
1426
|
+
throw Error(`No request object sign callback found, whilst request object mode was set to ${opts.requestObjectMode}`);
|
|
1427
|
+
} else if (!opts.kid) {
|
|
1428
|
+
throw Error(`No kid found, whilst request object mode was set to ${opts.requestObjectMode}`);
|
|
1429
|
+
}
|
|
1430
|
+
let client_metadata;
|
|
1431
|
+
if (opts.clientMetadata || opts.jwksUri) {
|
|
1432
|
+
client_metadata = opts.clientMetadata ?? {};
|
|
1433
|
+
if (opts.jwksUri) {
|
|
1434
|
+
client_metadata["jwks_uri"] = opts.jwksUri;
|
|
1435
|
+
}
|
|
1436
|
+
}
|
|
1437
|
+
let authorization_details = requestObject["authorization_details"];
|
|
1438
|
+
if (typeof authorization_details === "string") {
|
|
1439
|
+
authorization_details = JSON.parse(requestObject.authorization_details);
|
|
1440
|
+
}
|
|
1441
|
+
if (!requestObject.aud && opts.aud) {
|
|
1442
|
+
requestObject.aud = opts.aud;
|
|
1443
|
+
}
|
|
1444
|
+
const iss = requestObject.iss ?? opts.iss ?? requestObject.client_id;
|
|
1445
|
+
const jwt = {
|
|
1446
|
+
header: {
|
|
1447
|
+
alg: "ES256",
|
|
1448
|
+
kid: opts.kid,
|
|
1449
|
+
typ: "JWT"
|
|
1450
|
+
},
|
|
1451
|
+
payload: {
|
|
1452
|
+
...requestObject,
|
|
1453
|
+
iss,
|
|
1454
|
+
authorization_details,
|
|
1455
|
+
...client_metadata && {
|
|
1456
|
+
client_metadata
|
|
1457
|
+
}
|
|
1458
|
+
}
|
|
1459
|
+
};
|
|
1460
|
+
const pop = await ProofOfPossessionBuilder.fromJwt({
|
|
1461
|
+
jwt,
|
|
1462
|
+
callbacks: opts.signCallbacks,
|
|
1463
|
+
version: import_oid4vci_common13.OpenId4VCIVersion.VER_1_0_11,
|
|
1464
|
+
mode: "JWT"
|
|
1465
|
+
}).build();
|
|
1466
|
+
requestObject["request"] = pop.jwt;
|
|
1467
|
+
}
|
|
1468
|
+
}
|
|
1469
|
+
__name(createSignedAuthRequestWhenNeeded, "createSignedAuthRequestWhenNeeded");
|
|
1470
|
+
function filterSupportedCredentials(credentialOffer, credentialsSupported) {
|
|
1471
|
+
if (!credentialOffer.credential_configuration_ids || !credentialsSupported) {
|
|
1472
|
+
return [];
|
|
1473
|
+
}
|
|
1474
|
+
return Object.entries(credentialsSupported).filter((entry) => credentialOffer.credential_configuration_ids?.includes(entry[0])).map((entry) => {
|
|
1475
|
+
return {
|
|
1476
|
+
...entry[1],
|
|
1477
|
+
configuration_id: entry[0]
|
|
1478
|
+
};
|
|
1479
|
+
});
|
|
1480
|
+
}
|
|
1481
|
+
__name(filterSupportedCredentials, "filterSupportedCredentials");
|
|
1482
|
+
var createAuthorizationRequestUrl = /* @__PURE__ */ __name(async ({ pkce, endpointMetadata, authorizationRequest, credentialOffer, credentialConfigurationSupported, clientId, version }) => {
|
|
1483
|
+
function removeDisplayAndValueTypes(obj) {
|
|
1484
|
+
const newObj = {
|
|
1485
|
+
...obj
|
|
1486
|
+
};
|
|
1487
|
+
for (const prop in newObj) {
|
|
1488
|
+
if ([
|
|
1489
|
+
"display",
|
|
1490
|
+
"value_type"
|
|
1491
|
+
].includes(prop)) {
|
|
1492
|
+
delete newObj[prop];
|
|
1493
|
+
} else if (typeof newObj[prop] === "object") {
|
|
1494
|
+
newObj[prop] = removeDisplayAndValueTypes(newObj[prop]);
|
|
1495
|
+
}
|
|
1496
|
+
}
|
|
1497
|
+
return newObj;
|
|
1498
|
+
}
|
|
1499
|
+
__name(removeDisplayAndValueTypes, "removeDisplayAndValueTypes");
|
|
1500
|
+
const { redirectUri, requestObjectOpts = {
|
|
1501
|
+
requestObjectMode: import_oid4vci_common13.CreateRequestObjectMode.NONE
|
|
1502
|
+
} } = authorizationRequest;
|
|
1503
|
+
const client_id = clientId ?? authorizationRequest.clientId;
|
|
1504
|
+
const authorizationMetadata = endpointMetadata.authorizationServerMetadata ?? endpointMetadata.credentialIssuerMetadata;
|
|
1505
|
+
let { authorizationDetails } = authorizationRequest;
|
|
1506
|
+
const parMode = authorizationMetadata?.require_pushed_authorization_requests ? import_oid4vci_common13.PARMode.REQUIRE : authorizationRequest.parMode ?? (client_id ? import_oid4vci_common13.PARMode.AUTO : import_oid4vci_common13.PARMode.NEVER);
|
|
1507
|
+
if (!authorizationRequest.scope && !authorizationDetails) {
|
|
1508
|
+
if (!credentialOffer) {
|
|
1509
|
+
throw Error("Please provide a scope or authorization_details if no credential offer is present");
|
|
1510
|
+
}
|
|
1511
|
+
if ("credentials" in credentialOffer.credential_offer) {
|
|
1512
|
+
throw new Error("CredentialOffer format is wrong.");
|
|
1513
|
+
}
|
|
1514
|
+
const ver = version ?? (0, import_oid4vci_common13.determineSpecVersionFromOffer)(credentialOffer.credential_offer) ?? import_oid4vci_common13.OpenId4VCIVersion.VER_1_0_13;
|
|
1515
|
+
const creds = ver === import_oid4vci_common13.OpenId4VCIVersion.VER_1_0_13 ? filterSupportedCredentials(credentialOffer.credential_offer, credentialConfigurationSupported) : [];
|
|
1516
|
+
authorizationDetails = creds.flatMap((cred) => {
|
|
1517
|
+
const locations = [
|
|
1518
|
+
credentialOffer?.credential_offer.credential_issuer ?? endpointMetadata.issuer
|
|
1519
|
+
];
|
|
1520
|
+
const credential_configuration_id = cred.configuration_id;
|
|
1521
|
+
const format = credential_configuration_id ? void 0 : cred.format;
|
|
1522
|
+
if (!credential_configuration_id && !cred.format) {
|
|
1523
|
+
throw Error("format is required in authorization details");
|
|
1524
|
+
}
|
|
1525
|
+
const vct = cred.format === "vc+sd-jwt" ? cred.vct : void 0;
|
|
1526
|
+
const doctype = cred.format === "mso_mdoc" ? cred.doctype : void 0;
|
|
1527
|
+
let credential_definition = void 0;
|
|
1528
|
+
if ((0, import_oid4vci_common13.isW3cCredentialSupported)(cred)) {
|
|
1529
|
+
credential_definition = {
|
|
1530
|
+
...cred.credential_definition,
|
|
1531
|
+
// type: OPTIONAL. Array as defined in Appendix A.1.1.2. This claim contains the type values the Wallet requests authorization for at the Credential Issuer. It MUST be present if the claim format is present in the root of the authorization details object. It MUST not be present otherwise.
|
|
1532
|
+
// It meens we have a config_id, already mapping it to an explicit format and types
|
|
1533
|
+
type: format ? cred.credential_definition.type : void 0,
|
|
1534
|
+
credentialSubject: cred.credential_definition.credentialSubject ? removeDisplayAndValueTypes(cred.credential_definition.credentialSubject) : void 0
|
|
1535
|
+
};
|
|
1536
|
+
}
|
|
1537
|
+
return {
|
|
1538
|
+
type: "openid_credential",
|
|
1539
|
+
locations,
|
|
1540
|
+
...credential_definition && {
|
|
1541
|
+
credential_definition
|
|
1542
|
+
},
|
|
1543
|
+
...credential_configuration_id && {
|
|
1544
|
+
credential_configuration_id
|
|
1545
|
+
},
|
|
1546
|
+
...format && {
|
|
1547
|
+
format
|
|
1548
|
+
},
|
|
1549
|
+
...vct && {
|
|
1550
|
+
vct,
|
|
1551
|
+
claims: cred.claims ? removeDisplayAndValueTypes(cred.claims) : void 0
|
|
1552
|
+
},
|
|
1553
|
+
...doctype && {
|
|
1554
|
+
doctype,
|
|
1555
|
+
claims: cred.claims ? removeDisplayAndValueTypes(cred.claims) : void 0
|
|
1556
|
+
}
|
|
1557
|
+
};
|
|
1558
|
+
});
|
|
1559
|
+
if (!authorizationDetails || authorizationDetails.length === 0) {
|
|
1560
|
+
throw Error(`Could not create authorization details from credential offer. Please pass in explicit details`);
|
|
1561
|
+
}
|
|
1562
|
+
}
|
|
1563
|
+
if (!endpointMetadata?.authorization_endpoint) {
|
|
1564
|
+
throw Error("Server metadata does not contain authorization endpoint");
|
|
1565
|
+
}
|
|
1566
|
+
const parEndpoint = authorizationMetadata?.pushed_authorization_request_endpoint;
|
|
1567
|
+
let queryObj = {
|
|
1568
|
+
response_type: import_oid4vci_common13.ResponseType.AUTH_CODE,
|
|
1569
|
+
...!pkce.disabled && {
|
|
1570
|
+
code_challenge_method: pkce.codeChallengeMethod ?? import_oid4vci_common13.CodeChallengeMethod.S256,
|
|
1571
|
+
code_challenge: pkce.codeChallenge
|
|
1572
|
+
},
|
|
1573
|
+
authorization_details: JSON.stringify(handleAuthorizationDetails(endpointMetadata, authorizationDetails)),
|
|
1574
|
+
...redirectUri && {
|
|
1575
|
+
redirect_uri: redirectUri
|
|
1576
|
+
},
|
|
1577
|
+
...client_id && {
|
|
1578
|
+
client_id
|
|
1579
|
+
},
|
|
1580
|
+
...credentialOffer?.issuerState && {
|
|
1581
|
+
issuer_state: credentialOffer.issuerState
|
|
1582
|
+
},
|
|
1583
|
+
scope: authorizationRequest.scope
|
|
1584
|
+
};
|
|
1585
|
+
if (credentialOffer?.issuerState) {
|
|
1586
|
+
queryObj.state = credentialOffer?.issuerState;
|
|
1587
|
+
}
|
|
1588
|
+
if (!parEndpoint && parMode === import_oid4vci_common13.PARMode.REQUIRE) {
|
|
1589
|
+
throw Error(`PAR mode is set to required by Authorization Server does not support PAR!`);
|
|
1590
|
+
} else if (parEndpoint && parMode !== import_oid4vci_common13.PARMode.NEVER) {
|
|
1591
|
+
debug6(`USING PAR with endpoint ${parEndpoint}`);
|
|
1592
|
+
const parResponse = await (0, import_oid4vci_common13.formPost)(parEndpoint, (0, import_oid4vci_common13.convertJsonToURI)(queryObj, {
|
|
1593
|
+
mode: import_oid4vci_common13.JsonURIMode.X_FORM_WWW_URLENCODED,
|
|
1594
|
+
uriTypeProperties: [
|
|
1595
|
+
"client_id",
|
|
1596
|
+
"request_uri",
|
|
1597
|
+
"redirect_uri",
|
|
1598
|
+
"scope",
|
|
1599
|
+
"authorization_details",
|
|
1600
|
+
"issuer_state",
|
|
1601
|
+
"state"
|
|
1602
|
+
]
|
|
1603
|
+
}), {
|
|
1604
|
+
contentType: "application/x-www-form-urlencoded",
|
|
1605
|
+
accept: "application/json"
|
|
1606
|
+
});
|
|
1607
|
+
if (parResponse.errorBody || !parResponse.successBody) {
|
|
1608
|
+
if (parMode === import_oid4vci_common13.PARMode.REQUIRE) {
|
|
1609
|
+
throw Error(`PAR error: ${parResponse.origResponse.statusText}`);
|
|
1610
|
+
}
|
|
1611
|
+
debug6("Falling back to regular request URI, since PAR failed", JSON.stringify(parResponse.errorBody));
|
|
1612
|
+
} else {
|
|
1613
|
+
debug6(`PAR response: ${JSON.stringify(parResponse.successBody, null, 2)}`);
|
|
1614
|
+
queryObj = {
|
|
1615
|
+
client_id,
|
|
1616
|
+
request_uri: parResponse.successBody.request_uri
|
|
1617
|
+
};
|
|
1618
|
+
}
|
|
1619
|
+
}
|
|
1620
|
+
await createSignedAuthRequestWhenNeeded(queryObj, {
|
|
1621
|
+
...requestObjectOpts,
|
|
1622
|
+
aud: endpointMetadata.authorization_server
|
|
1623
|
+
});
|
|
1624
|
+
debug6(`Object that will become query params: ` + JSON.stringify(queryObj, null, 2));
|
|
1625
|
+
const url = (0, import_oid4vci_common13.convertJsonToURI)(queryObj, {
|
|
1626
|
+
baseUrl: endpointMetadata.authorization_endpoint,
|
|
1627
|
+
uriTypeProperties: [
|
|
1628
|
+
"client_id",
|
|
1629
|
+
"request_uri",
|
|
1630
|
+
"redirect_uri",
|
|
1631
|
+
"scope",
|
|
1632
|
+
"authorization_details",
|
|
1633
|
+
"issuer_state",
|
|
1634
|
+
"state"
|
|
1635
|
+
],
|
|
1636
|
+
// arrayTypeProperties: ['authorization_details'],
|
|
1637
|
+
mode: import_oid4vci_common13.JsonURIMode.X_FORM_WWW_URLENCODED
|
|
1638
|
+
});
|
|
1639
|
+
debug6(`Authorization Request URL: ${url}`);
|
|
1640
|
+
return url;
|
|
1641
|
+
}, "createAuthorizationRequestUrl");
|
|
1642
|
+
var handleAuthorizationDetails = /* @__PURE__ */ __name((endpointMetadata, authorizationDetails) => {
|
|
1643
|
+
if (authorizationDetails) {
|
|
1644
|
+
if (typeof authorizationDetails === "string") {
|
|
1645
|
+
return authorizationDetails;
|
|
1646
|
+
}
|
|
1647
|
+
if (Array.isArray(authorizationDetails)) {
|
|
1648
|
+
return authorizationDetails.filter((value) => typeof value !== "string").map((value) => handleLocations(endpointMetadata, typeof value === "string" ? value : {
|
|
1649
|
+
...value
|
|
1650
|
+
}));
|
|
1651
|
+
} else {
|
|
1652
|
+
return handleLocations(endpointMetadata, {
|
|
1653
|
+
...authorizationDetails
|
|
1654
|
+
});
|
|
1655
|
+
}
|
|
1656
|
+
}
|
|
1657
|
+
return authorizationDetails;
|
|
1658
|
+
}, "handleAuthorizationDetails");
|
|
1659
|
+
var handleLocations = /* @__PURE__ */ __name((endpointMetadata, authorizationDetails) => {
|
|
1660
|
+
if (typeof authorizationDetails === "string") {
|
|
1661
|
+
return authorizationDetails;
|
|
1662
|
+
}
|
|
1663
|
+
if (authorizationDetails && (endpointMetadata.credentialIssuerMetadata?.authorization_server || endpointMetadata.authorization_endpoint)) {
|
|
1664
|
+
if (authorizationDetails.locations) {
|
|
1665
|
+
if (Array.isArray(authorizationDetails.locations)) {
|
|
1666
|
+
authorizationDetails.locations.push(endpointMetadata.issuer);
|
|
1667
|
+
} else {
|
|
1668
|
+
authorizationDetails.locations = [
|
|
1669
|
+
authorizationDetails.locations,
|
|
1670
|
+
endpointMetadata.issuer
|
|
1671
|
+
];
|
|
1672
|
+
}
|
|
1673
|
+
} else {
|
|
1674
|
+
authorizationDetails.locations = [
|
|
1675
|
+
endpointMetadata.issuer
|
|
1676
|
+
];
|
|
1677
|
+
}
|
|
1678
|
+
}
|
|
1679
|
+
return authorizationDetails;
|
|
1680
|
+
}, "handleLocations");
|
|
1681
|
+
var acquireAuthorizationChallengeAuthCode = /* @__PURE__ */ __name(async (opts) => {
|
|
1682
|
+
const { metadata } = opts;
|
|
1683
|
+
const issuer = opts.credentialIssuer ?? opts?.metadata?.issuer;
|
|
1684
|
+
if (!issuer) {
|
|
1685
|
+
throw Error("Issuer required at this point");
|
|
1686
|
+
}
|
|
1687
|
+
const issuerOpts = {
|
|
1688
|
+
issuer
|
|
1689
|
+
};
|
|
1690
|
+
return await acquireAuthorizationChallengeAuthCodeUsingRequest({
|
|
1691
|
+
authorizationChallengeRequest: await createAuthorizationChallengeRequest(opts),
|
|
1692
|
+
metadata,
|
|
1693
|
+
issuerOpts
|
|
1694
|
+
});
|
|
1695
|
+
}, "acquireAuthorizationChallengeAuthCode");
|
|
1696
|
+
var acquireAuthorizationChallengeAuthCodeUsingRequest = /* @__PURE__ */ __name(async (opts) => {
|
|
1697
|
+
const { authorizationChallengeRequest, issuerOpts } = opts;
|
|
1698
|
+
const metadata = opts?.metadata ? opts?.metadata : issuerOpts?.fetchMetadata ? await MetadataClient.retrieveAllMetadata(issuerOpts.issuer, {
|
|
1699
|
+
errorOnNotFound: false
|
|
1700
|
+
}) : void 0;
|
|
1701
|
+
const authorizationChallengeCodeUrl = metadata?.authorization_challenge_endpoint;
|
|
1702
|
+
if (!authorizationChallengeCodeUrl) {
|
|
1703
|
+
return Promise.reject(Error("Cannot determine authorization challenge endpoint URL"));
|
|
1704
|
+
}
|
|
1705
|
+
const response = await sendAuthorizationChallengeRequest(authorizationChallengeCodeUrl, authorizationChallengeRequest);
|
|
1706
|
+
return response;
|
|
1707
|
+
}, "acquireAuthorizationChallengeAuthCodeUsingRequest");
|
|
1708
|
+
var createAuthorizationChallengeRequest = /* @__PURE__ */ __name(async (opts) => {
|
|
1709
|
+
const { clientId, issuerState, authSession, scope, codeChallenge, codeChallengeMethod, presentationDuringIssuanceSession } = opts;
|
|
1710
|
+
const request = {
|
|
1711
|
+
client_id: clientId,
|
|
1712
|
+
issuer_state: issuerState,
|
|
1713
|
+
auth_session: authSession,
|
|
1714
|
+
scope,
|
|
1715
|
+
code_challenge: codeChallenge,
|
|
1716
|
+
code_challenge_method: codeChallengeMethod,
|
|
1717
|
+
presentation_during_issuance_session: presentationDuringIssuanceSession
|
|
1718
|
+
};
|
|
1719
|
+
return request;
|
|
1720
|
+
}, "createAuthorizationChallengeRequest");
|
|
1721
|
+
var sendAuthorizationChallengeRequest = /* @__PURE__ */ __name(async (authorizationChallengeCodeUrl, authorizationChallengeRequest, opts) => {
|
|
1722
|
+
return await (0, import_oid4vci_common13.formPost)(authorizationChallengeCodeUrl, (0, import_oid4vci_common13.convertJsonToURI)(authorizationChallengeRequest, {
|
|
1723
|
+
mode: import_oid4vci_common13.JsonURIMode.X_FORM_WWW_URLENCODED
|
|
1724
|
+
}), {
|
|
1725
|
+
customHeaders: opts?.headers ? opts.headers : void 0
|
|
1726
|
+
});
|
|
1727
|
+
}, "sendAuthorizationChallengeRequest");
|
|
1728
|
+
|
|
1729
|
+
// lib/AuthorizationCodeClientV1_0_11.ts
|
|
1730
|
+
var import_oid4vci_common14 = require("@sphereon/oid4vci-common");
|
|
1731
|
+
var import_debug7 = __toESM(require("debug"), 1);
|
|
1732
|
+
var debug7 = (0, import_debug7.default)("sphereon:oid4vci");
|
|
1733
|
+
var createAuthorizationRequestUrlV1_0_11 = /* @__PURE__ */ __name(async ({ pkce, endpointMetadata, authorizationRequest, credentialOffer, credentialsSupported }) => {
|
|
1734
|
+
const { redirectUri, clientId, requestObjectOpts = {
|
|
1735
|
+
requestObjectMode: import_oid4vci_common14.CreateRequestObjectMode.NONE
|
|
1736
|
+
} } = authorizationRequest;
|
|
1737
|
+
let { scope, authorizationDetails } = authorizationRequest;
|
|
1738
|
+
const parMode = endpointMetadata?.credentialIssuerMetadata?.require_pushed_authorization_requests ? import_oid4vci_common14.PARMode.REQUIRE : authorizationRequest.parMode ?? import_oid4vci_common14.PARMode.AUTO;
|
|
1739
|
+
if (!scope && !authorizationDetails) {
|
|
1740
|
+
if (!credentialOffer) {
|
|
1741
|
+
throw Error("Please provide a scope or authorization_details if no credential offer is present");
|
|
1742
|
+
}
|
|
1743
|
+
const creds = credentialOffer.credential_offer.credentials;
|
|
1744
|
+
authorizationDetails = creds.flatMap((cred) => typeof cred === "string" ? credentialsSupported : cred).filter((cred) => !!cred).map((cred) => {
|
|
1745
|
+
return {
|
|
1746
|
+
...cred,
|
|
1747
|
+
type: "openid_credential",
|
|
1748
|
+
locations: [
|
|
1749
|
+
endpointMetadata.issuer
|
|
1750
|
+
],
|
|
1751
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
1752
|
+
// @ts-ignore
|
|
1753
|
+
format: cred.format
|
|
1754
|
+
};
|
|
1755
|
+
});
|
|
1756
|
+
if (!authorizationDetails || Array.isArray(authorizationDetails) && authorizationDetails.length === 0) {
|
|
1757
|
+
throw Error(`Could not create authorization details from credential offer. Please pass in explicit details`);
|
|
1758
|
+
}
|
|
1759
|
+
}
|
|
1760
|
+
if (!endpointMetadata?.authorization_endpoint) {
|
|
1761
|
+
throw Error("Server metadata does not contain authorization endpoint");
|
|
1762
|
+
}
|
|
1763
|
+
const parEndpoint = endpointMetadata.credentialIssuerMetadata?.pushed_authorization_request_endpoint;
|
|
1764
|
+
if (!scope?.includes("openid")) {
|
|
1765
|
+
scope = [
|
|
1766
|
+
"openid",
|
|
1767
|
+
scope
|
|
1768
|
+
].filter((s) => !!s).join(" ");
|
|
1769
|
+
}
|
|
1770
|
+
let queryObj = {
|
|
1771
|
+
response_type: import_oid4vci_common14.ResponseType.AUTH_CODE,
|
|
1772
|
+
...!pkce.disabled && {
|
|
1773
|
+
code_challenge_method: pkce.codeChallengeMethod ?? import_oid4vci_common14.CodeChallengeMethod.S256,
|
|
1774
|
+
code_challenge: pkce.codeChallenge
|
|
1775
|
+
},
|
|
1776
|
+
authorization_details: JSON.stringify(handleAuthorizationDetailsV1_0_11(endpointMetadata, authorizationDetails)),
|
|
1777
|
+
...redirectUri && {
|
|
1778
|
+
redirect_uri: redirectUri
|
|
1779
|
+
},
|
|
1780
|
+
...clientId && {
|
|
1781
|
+
client_id: clientId
|
|
1782
|
+
},
|
|
1783
|
+
...credentialOffer?.issuerState && {
|
|
1784
|
+
issuer_state: credentialOffer.issuerState
|
|
1785
|
+
},
|
|
1786
|
+
scope
|
|
1787
|
+
};
|
|
1788
|
+
if (!parEndpoint && parMode === import_oid4vci_common14.PARMode.REQUIRE) {
|
|
1789
|
+
throw Error(`PAR mode is set to required by Authorization Server does not support PAR!`);
|
|
1790
|
+
} else if (parEndpoint && parMode !== import_oid4vci_common14.PARMode.NEVER) {
|
|
1791
|
+
debug7(`USING PAR with endpoint ${parEndpoint}`);
|
|
1792
|
+
const parResponse = await (0, import_oid4vci_common14.formPost)(parEndpoint, (0, import_oid4vci_common14.convertJsonToURI)(queryObj, {
|
|
1793
|
+
mode: import_oid4vci_common14.JsonURIMode.X_FORM_WWW_URLENCODED,
|
|
1794
|
+
uriTypeProperties: [
|
|
1795
|
+
"client_id",
|
|
1796
|
+
"request_uri",
|
|
1797
|
+
"redirect_uri",
|
|
1798
|
+
"scope",
|
|
1799
|
+
"authorization_details",
|
|
1800
|
+
"issuer_state"
|
|
1801
|
+
]
|
|
1802
|
+
}), {
|
|
1803
|
+
contentType: "application/x-www-form-urlencoded",
|
|
1804
|
+
accept: "application/json"
|
|
1805
|
+
});
|
|
1806
|
+
if (parResponse.errorBody || !parResponse.successBody) {
|
|
1807
|
+
console.log(JSON.stringify(parResponse.errorBody));
|
|
1808
|
+
console.log("Falling back to regular request URI, since PAR failed");
|
|
1809
|
+
if (parMode === import_oid4vci_common14.PARMode.REQUIRE) {
|
|
1810
|
+
throw Error(`PAR error: ${parResponse.origResponse.statusText}`);
|
|
1811
|
+
}
|
|
1812
|
+
} else {
|
|
1813
|
+
debug7(`PAR response: ${JSON.stringify(parResponse.successBody, null, 2)}`);
|
|
1814
|
+
queryObj = {
|
|
1815
|
+
request_uri: parResponse.successBody.request_uri
|
|
1816
|
+
};
|
|
1817
|
+
}
|
|
1818
|
+
}
|
|
1819
|
+
await createSignedAuthRequestWhenNeeded(queryObj, {
|
|
1820
|
+
...requestObjectOpts,
|
|
1821
|
+
aud: endpointMetadata.authorization_server
|
|
1822
|
+
});
|
|
1823
|
+
debug7(`Object that will become query params: ` + JSON.stringify(queryObj, null, 2));
|
|
1824
|
+
const url = (0, import_oid4vci_common14.convertJsonToURI)(queryObj, {
|
|
1825
|
+
baseUrl: endpointMetadata.authorization_endpoint,
|
|
1826
|
+
uriTypeProperties: [
|
|
1827
|
+
"client_id",
|
|
1828
|
+
"request_uri",
|
|
1829
|
+
"redirect_uri",
|
|
1830
|
+
"scope",
|
|
1831
|
+
"authorization_details",
|
|
1832
|
+
"issuer_state"
|
|
1833
|
+
],
|
|
1834
|
+
// arrayTypeProperties: ['authorization_details'],
|
|
1835
|
+
mode: import_oid4vci_common14.JsonURIMode.X_FORM_WWW_URLENCODED
|
|
1836
|
+
});
|
|
1837
|
+
debug7(`Authorization Request URL: ${url}`);
|
|
1838
|
+
return url;
|
|
1839
|
+
}, "createAuthorizationRequestUrlV1_0_11");
|
|
1840
|
+
var handleAuthorizationDetailsV1_0_11 = /* @__PURE__ */ __name((endpointMetadata, authorizationDetails) => {
|
|
1841
|
+
if (authorizationDetails) {
|
|
1842
|
+
if (typeof authorizationDetails === "string") {
|
|
1843
|
+
return authorizationDetails;
|
|
1844
|
+
}
|
|
1845
|
+
if (Array.isArray(authorizationDetails)) {
|
|
1846
|
+
return authorizationDetails.filter((value) => typeof value !== "string").map((value) => handleLocations2(endpointMetadata, typeof value === "string" ? value : {
|
|
1847
|
+
...value
|
|
1848
|
+
}));
|
|
1849
|
+
} else {
|
|
1850
|
+
return handleLocations2(endpointMetadata, {
|
|
1851
|
+
...authorizationDetails
|
|
1852
|
+
});
|
|
1853
|
+
}
|
|
1854
|
+
}
|
|
1855
|
+
return authorizationDetails;
|
|
1856
|
+
}, "handleAuthorizationDetailsV1_0_11");
|
|
1857
|
+
var handleLocations2 = /* @__PURE__ */ __name((endpointMetadata, authorizationDetails) => {
|
|
1858
|
+
if (typeof authorizationDetails === "string") {
|
|
1859
|
+
return authorizationDetails;
|
|
1860
|
+
}
|
|
1861
|
+
if (authorizationDetails && (endpointMetadata.credentialIssuerMetadata?.authorization_server || endpointMetadata.authorization_endpoint)) {
|
|
1862
|
+
if (authorizationDetails.locations) {
|
|
1863
|
+
if (Array.isArray(authorizationDetails.locations)) {
|
|
1864
|
+
authorizationDetails.locations.push(endpointMetadata.issuer);
|
|
1865
|
+
} else {
|
|
1866
|
+
authorizationDetails.locations = [
|
|
1867
|
+
authorizationDetails.locations,
|
|
1868
|
+
endpointMetadata.issuer
|
|
1869
|
+
];
|
|
1870
|
+
}
|
|
1871
|
+
} else {
|
|
1872
|
+
authorizationDetails.locations = [
|
|
1873
|
+
endpointMetadata.issuer
|
|
1874
|
+
];
|
|
1875
|
+
}
|
|
1876
|
+
}
|
|
1877
|
+
return authorizationDetails;
|
|
1878
|
+
}, "handleLocations");
|
|
1879
|
+
|
|
1880
|
+
// lib/CredentialRequestClient.ts
|
|
1881
|
+
var import_oid4vc_common5 = require("@sphereon/oid4vc-common");
|
|
1882
|
+
var import_oid4vci_common15 = require("@sphereon/oid4vci-common");
|
|
1883
|
+
var import_debug8 = __toESM(require("debug"), 1);
|
|
1884
|
+
var debug8 = (0, import_debug8.default)("sphereon:oid4vci:credential");
|
|
1885
|
+
async function buildProof(proofInput, opts) {
|
|
1886
|
+
if ("proof_type" in proofInput) {
|
|
1887
|
+
if (opts.cNonce) {
|
|
1888
|
+
throw Error(`Cnonce param is only supported when using a Proof of possession builder`);
|
|
1889
|
+
}
|
|
1890
|
+
return await ProofOfPossessionBuilder.fromProof(proofInput, opts.version).build();
|
|
1891
|
+
}
|
|
1892
|
+
if (opts.cNonce) {
|
|
1893
|
+
proofInput.withAccessTokenNonce(opts.cNonce);
|
|
1894
|
+
}
|
|
1895
|
+
return await proofInput.build();
|
|
1896
|
+
}
|
|
1897
|
+
__name(buildProof, "buildProof");
|
|
1898
|
+
var CredentialRequestClient = class {
|
|
1899
|
+
static {
|
|
1900
|
+
__name(this, "CredentialRequestClient");
|
|
1901
|
+
}
|
|
1902
|
+
_credentialRequestOpts;
|
|
1903
|
+
_isDeferred = false;
|
|
1904
|
+
get credentialRequestOpts() {
|
|
1905
|
+
return this._credentialRequestOpts;
|
|
1906
|
+
}
|
|
1907
|
+
isDeferred() {
|
|
1908
|
+
return this._isDeferred;
|
|
1909
|
+
}
|
|
1910
|
+
getCredentialEndpoint() {
|
|
1911
|
+
return this.credentialRequestOpts.credentialEndpoint;
|
|
1912
|
+
}
|
|
1913
|
+
getDeferredCredentialEndpoint() {
|
|
1914
|
+
return this.credentialRequestOpts.deferredCredentialEndpoint;
|
|
1915
|
+
}
|
|
1916
|
+
constructor(builder) {
|
|
1917
|
+
this._credentialRequestOpts = {
|
|
1918
|
+
...builder
|
|
1919
|
+
};
|
|
1920
|
+
}
|
|
1921
|
+
/**
|
|
1922
|
+
* Typically you should not use this method, as it omits a proof from the request.
|
|
1923
|
+
* There are certain issuers that in specific circumstances can do without this proof, because they have other means of user binding
|
|
1924
|
+
* like using DPoP together with an authorization code flow. These are however rare, so you should be using the acquireCredentialsUsingProof normally
|
|
1925
|
+
* @param opts
|
|
1926
|
+
*/
|
|
1927
|
+
async acquireCredentialsWithoutProof(opts) {
|
|
1928
|
+
const { credentialIdentifier, credentialTypes, format, context, subjectIssuance } = opts;
|
|
1929
|
+
const request = await this.createCredentialRequestWithoutProof({
|
|
1930
|
+
credentialTypes,
|
|
1931
|
+
context,
|
|
1932
|
+
format,
|
|
1933
|
+
version: this.version(),
|
|
1934
|
+
credentialIdentifier,
|
|
1935
|
+
subjectIssuance
|
|
1936
|
+
});
|
|
1937
|
+
return await this.acquireCredentialsUsingRequestWithoutProof(request, opts.createDPoPOpts);
|
|
1938
|
+
}
|
|
1939
|
+
async acquireCredentialsUsingProof(opts) {
|
|
1940
|
+
const { credentialIdentifier, credentialTypes, proofInput, format, context, subjectIssuance } = opts;
|
|
1941
|
+
const request = await this.createCredentialRequest({
|
|
1942
|
+
proofInput,
|
|
1943
|
+
credentialTypes,
|
|
1944
|
+
context,
|
|
1945
|
+
format,
|
|
1946
|
+
version: this.version(),
|
|
1947
|
+
credentialIdentifier,
|
|
1948
|
+
subjectIssuance
|
|
1949
|
+
});
|
|
1950
|
+
return await this.acquireCredentialsUsingRequest(request, opts.createDPoPOpts);
|
|
1951
|
+
}
|
|
1952
|
+
async acquireCredentialsUsingRequestWithoutProof(uniformRequest, createDPoPOpts) {
|
|
1953
|
+
return await this.acquireCredentialsUsingRequestImpl(uniformRequest, createDPoPOpts);
|
|
1954
|
+
}
|
|
1955
|
+
async acquireCredentialsUsingRequest(uniformRequest, createDPoPOpts) {
|
|
1956
|
+
return await this.acquireCredentialsUsingRequestImpl(uniformRequest, createDPoPOpts);
|
|
1957
|
+
}
|
|
1958
|
+
async acquireCredentialsUsingRequestImpl(uniformRequest, createDPoPOpts) {
|
|
1959
|
+
if (this.version() < import_oid4vci_common15.OpenId4VCIVersion.VER_1_0_13) {
|
|
1960
|
+
throw new Error("Versions below v1.0.13 (draft 13) are not supported by the V13 credential request client.");
|
|
1961
|
+
}
|
|
1962
|
+
const request = (0, import_oid4vci_common15.getCredentialRequestForVersion)(uniformRequest, this.version());
|
|
1963
|
+
const credentialEndpoint = this.credentialRequestOpts.credentialEndpoint;
|
|
1964
|
+
if (!(0, import_oid4vci_common15.isValidURL)(credentialEndpoint)) {
|
|
1965
|
+
debug8(`Invalid credential endpoint: ${credentialEndpoint}`);
|
|
1966
|
+
throw new Error(import_oid4vci_common15.URL_NOT_VALID);
|
|
1967
|
+
}
|
|
1968
|
+
debug8(`Acquiring credential(s) from: ${credentialEndpoint}`);
|
|
1969
|
+
debug8(`request
|
|
1970
|
+
: ${JSON.stringify(request, null, 2)}`);
|
|
1971
|
+
const requestToken = this.credentialRequestOpts.token;
|
|
1972
|
+
let dPoP = createDPoPOpts ? await (0, import_oid4vc_common5.createDPoP)((0, import_oid4vc_common5.getCreateDPoPOptions)(createDPoPOpts, credentialEndpoint, {
|
|
1973
|
+
accessToken: requestToken
|
|
1974
|
+
})) : void 0;
|
|
1975
|
+
let response = await (0, import_oid4vci_common15.post)(credentialEndpoint, JSON.stringify(request), {
|
|
1976
|
+
bearerToken: requestToken,
|
|
1977
|
+
...dPoP && {
|
|
1978
|
+
customHeaders: {
|
|
1979
|
+
dpop: dPoP
|
|
1980
|
+
}
|
|
1981
|
+
}
|
|
1982
|
+
});
|
|
1983
|
+
let nextDPoPNonce = createDPoPOpts?.jwtPayloadProps.nonce;
|
|
1984
|
+
const retryWithNonce = shouldRetryResourceRequestWithDPoPNonce(response);
|
|
1985
|
+
if (retryWithNonce.ok && createDPoPOpts) {
|
|
1986
|
+
createDPoPOpts.jwtPayloadProps.nonce = retryWithNonce.dpopNonce;
|
|
1987
|
+
dPoP = await (0, import_oid4vc_common5.createDPoP)((0, import_oid4vc_common5.getCreateDPoPOptions)(createDPoPOpts, credentialEndpoint, {
|
|
1988
|
+
accessToken: requestToken
|
|
1989
|
+
}));
|
|
1990
|
+
response = await (0, import_oid4vci_common15.post)(credentialEndpoint, JSON.stringify(request), {
|
|
1991
|
+
bearerToken: requestToken,
|
|
1992
|
+
...createDPoPOpts && {
|
|
1993
|
+
customHeaders: {
|
|
1994
|
+
dpop: dPoP
|
|
1995
|
+
}
|
|
1996
|
+
}
|
|
1997
|
+
});
|
|
1998
|
+
const successDPoPNonce = response.origResponse.headers.get("DPoP-Nonce");
|
|
1999
|
+
nextDPoPNonce = successDPoPNonce ?? retryWithNonce.dpopNonce;
|
|
2000
|
+
}
|
|
2001
|
+
this._isDeferred = (0, import_oid4vci_common15.isDeferredCredentialResponse)(response);
|
|
2002
|
+
if (this.isDeferred() && this.credentialRequestOpts.deferredCredentialAwait && response.successBody) {
|
|
2003
|
+
response = await this.acquireDeferredCredential(response.successBody, {
|
|
2004
|
+
bearerToken: this.credentialRequestOpts.token
|
|
2005
|
+
});
|
|
2006
|
+
}
|
|
2007
|
+
response.access_token = requestToken;
|
|
2008
|
+
if (uniformRequest.credential_subject_issuance && response.successBody || response.successBody?.credential_subject_issuance) {
|
|
2009
|
+
if (JSON.stringify(uniformRequest.credential_subject_issuance) !== JSON.stringify(response.successBody?.credential_subject_issuance)) {
|
|
2010
|
+
throw Error("Subject signing was requested, but issuer did not provide the options in its response");
|
|
2011
|
+
}
|
|
2012
|
+
}
|
|
2013
|
+
debug8(`Credential endpoint ${credentialEndpoint} response:\r
|
|
2014
|
+
${JSON.stringify(response, null, 2)}`);
|
|
2015
|
+
return {
|
|
2016
|
+
...response,
|
|
2017
|
+
...nextDPoPNonce && {
|
|
2018
|
+
params: {
|
|
2019
|
+
dpop: {
|
|
2020
|
+
dpopNonce: nextDPoPNonce
|
|
2021
|
+
}
|
|
2022
|
+
}
|
|
2023
|
+
}
|
|
2024
|
+
};
|
|
2025
|
+
}
|
|
2026
|
+
async acquireDeferredCredential(response, opts) {
|
|
2027
|
+
const transactionId = response.transaction_id;
|
|
2028
|
+
const bearerToken = response.acceptance_token ?? opts?.bearerToken;
|
|
2029
|
+
const deferredCredentialEndpoint = this.getDeferredCredentialEndpoint();
|
|
2030
|
+
if (!deferredCredentialEndpoint) {
|
|
2031
|
+
throw Error(`No deferred credential endpoint supplied.`);
|
|
2032
|
+
} else if (!bearerToken) {
|
|
2033
|
+
throw Error(`No bearer token present and refresh for defered endpoint not supported yet`);
|
|
2034
|
+
}
|
|
2035
|
+
return await (0, import_oid4vci_common15.acquireDeferredCredential)({
|
|
2036
|
+
bearerToken,
|
|
2037
|
+
transactionId,
|
|
2038
|
+
deferredCredentialEndpoint,
|
|
2039
|
+
deferredCredentialAwait: this.credentialRequestOpts.deferredCredentialAwait,
|
|
2040
|
+
deferredCredentialIntervalInMS: this.credentialRequestOpts.deferredCredentialIntervalInMS
|
|
2041
|
+
});
|
|
2042
|
+
}
|
|
2043
|
+
async createCredentialRequestWithoutProof(opts) {
|
|
2044
|
+
return await this.createCredentialRequestImpl(opts);
|
|
2045
|
+
}
|
|
2046
|
+
async createCredentialRequest(opts) {
|
|
2047
|
+
return await this.createCredentialRequestImpl(opts);
|
|
2048
|
+
}
|
|
2049
|
+
async createCredentialRequestImpl(opts) {
|
|
2050
|
+
const { proofInput, credentialIdentifier: credential_identifier } = opts;
|
|
2051
|
+
let proof = void 0;
|
|
2052
|
+
if (proofInput) {
|
|
2053
|
+
proof = await buildProof(proofInput, opts);
|
|
2054
|
+
}
|
|
2055
|
+
if (credential_identifier) {
|
|
2056
|
+
if (opts.format || opts.credentialTypes || opts.context) {
|
|
2057
|
+
throw Error(`You cannot mix credential_identifier with format, credential types and/or context`);
|
|
2058
|
+
}
|
|
2059
|
+
return {
|
|
2060
|
+
credential_identifier,
|
|
2061
|
+
...proof && {
|
|
2062
|
+
proof
|
|
2063
|
+
}
|
|
2064
|
+
};
|
|
2065
|
+
}
|
|
2066
|
+
const formatSelection = opts.format ?? this.credentialRequestOpts.format;
|
|
2067
|
+
if (!formatSelection) {
|
|
2068
|
+
throw Error(`Format of credential to be issued is missing`);
|
|
2069
|
+
}
|
|
2070
|
+
const format = (0, import_oid4vci_common15.getUniformFormat)(formatSelection);
|
|
2071
|
+
const typesSelection = opts?.credentialTypes && (typeof opts.credentialTypes === "string" || opts.credentialTypes.length > 0) ? opts.credentialTypes : this.credentialRequestOpts.credentialTypes;
|
|
2072
|
+
if (!typesSelection) {
|
|
2073
|
+
throw Error(`Credential type(s) need to be provided`);
|
|
2074
|
+
}
|
|
2075
|
+
const types = Array.isArray(typesSelection) ? typesSelection : [
|
|
2076
|
+
typesSelection
|
|
2077
|
+
];
|
|
2078
|
+
if (types.length === 0) {
|
|
2079
|
+
throw Error(`Credential type(s) need to be provided`);
|
|
2080
|
+
}
|
|
2081
|
+
const issuer_state = this.credentialRequestOpts.issuerState;
|
|
2082
|
+
if (format === "jwt_vc_json" || format === "jwt_vc") {
|
|
2083
|
+
return {
|
|
2084
|
+
credential_definition: {
|
|
2085
|
+
type: types
|
|
2086
|
+
},
|
|
2087
|
+
format,
|
|
2088
|
+
...issuer_state && {
|
|
2089
|
+
issuer_state
|
|
2090
|
+
},
|
|
2091
|
+
...proof && {
|
|
2092
|
+
proof
|
|
2093
|
+
},
|
|
2094
|
+
...opts.subjectIssuance
|
|
2095
|
+
};
|
|
2096
|
+
} else if (format === "jwt_vc_json-ld" || format === "ldp_vc") {
|
|
2097
|
+
if (this.version() >= import_oid4vci_common15.OpenId4VCIVersion.VER_1_0_12 && !opts.context) {
|
|
2098
|
+
throw Error("No @context value present, but it is required");
|
|
2099
|
+
}
|
|
2100
|
+
return {
|
|
2101
|
+
format,
|
|
2102
|
+
...issuer_state && {
|
|
2103
|
+
issuer_state
|
|
2104
|
+
},
|
|
2105
|
+
...proof && {
|
|
2106
|
+
proof
|
|
2107
|
+
},
|
|
2108
|
+
...opts.subjectIssuance,
|
|
2109
|
+
credential_definition: {
|
|
2110
|
+
type: types,
|
|
2111
|
+
"@context": opts.context
|
|
2112
|
+
}
|
|
2113
|
+
};
|
|
2114
|
+
} else if (format === "vc+sd-jwt") {
|
|
2115
|
+
if (types.length > 1) {
|
|
2116
|
+
throw Error(`Only a single credential type is supported for ${format}`);
|
|
2117
|
+
}
|
|
2118
|
+
return {
|
|
2119
|
+
format,
|
|
2120
|
+
...issuer_state && {
|
|
2121
|
+
issuer_state
|
|
2122
|
+
},
|
|
2123
|
+
...proof && {
|
|
2124
|
+
proof
|
|
2125
|
+
},
|
|
2126
|
+
vct: types[0],
|
|
2127
|
+
...opts.subjectIssuance
|
|
2128
|
+
};
|
|
2129
|
+
} else if (format === "mso_mdoc") {
|
|
2130
|
+
if (types.length > 1) {
|
|
2131
|
+
throw Error(`Only a single credential type is supported for ${format}`);
|
|
2132
|
+
}
|
|
2133
|
+
return {
|
|
2134
|
+
format,
|
|
2135
|
+
...issuer_state && {
|
|
2136
|
+
issuer_state
|
|
2137
|
+
},
|
|
2138
|
+
...proof && {
|
|
2139
|
+
proof
|
|
2140
|
+
},
|
|
2141
|
+
doctype: types[0],
|
|
2142
|
+
...opts.subjectIssuance
|
|
2143
|
+
};
|
|
2144
|
+
}
|
|
2145
|
+
throw new Error(`Unsupported credential format: ${format}`);
|
|
2146
|
+
}
|
|
2147
|
+
version() {
|
|
2148
|
+
return this.credentialRequestOpts?.version ?? import_oid4vci_common15.OpenId4VCIVersion.VER_1_0_13;
|
|
2149
|
+
}
|
|
2150
|
+
};
|
|
2151
|
+
|
|
2152
|
+
// lib/CredentialOfferClient.ts
|
|
2153
|
+
var import_oid4vci_common16 = require("@sphereon/oid4vci-common");
|
|
2154
|
+
var import_debug9 = __toESM(require("debug"), 1);
|
|
2155
|
+
var debug9 = (0, import_debug9.default)("sphereon:oid4vci:offer");
|
|
2156
|
+
var CredentialOfferClient = class {
|
|
2157
|
+
static {
|
|
2158
|
+
__name(this, "CredentialOfferClient");
|
|
2159
|
+
}
|
|
2160
|
+
static async fromURI(uri, opts) {
|
|
2161
|
+
debug9(`Credential Offer URI: ${uri}`);
|
|
2162
|
+
if (!uri.includes("?") || !uri.includes("://")) {
|
|
2163
|
+
debug9(`Invalid Credential Offer URI: ${uri}`);
|
|
2164
|
+
throw Error(`Invalid Credential Offer Request`);
|
|
2165
|
+
}
|
|
2166
|
+
const scheme = uri.split("://")[0];
|
|
2167
|
+
const baseUrl = uri.split("?")[0];
|
|
2168
|
+
const version = (0, import_oid4vci_common16.determineSpecVersionFromURI)(uri);
|
|
2169
|
+
LOG.log(`Offer URL determined to be of version ${version}`);
|
|
2170
|
+
let credentialOffer;
|
|
2171
|
+
let credentialOfferPayload;
|
|
2172
|
+
if (version < import_oid4vci_common16.OpenId4VCIVersion.VER_1_0_11) {
|
|
2173
|
+
credentialOfferPayload = (0, import_oid4vci_common16.convertURIToJsonObject)(uri, {
|
|
2174
|
+
arrayTypeProperties: [
|
|
2175
|
+
"credential_type"
|
|
2176
|
+
],
|
|
2177
|
+
requiredProperties: uri.includes("credential_offer=") ? [
|
|
2178
|
+
"credential_offer"
|
|
2179
|
+
] : [
|
|
2180
|
+
"issuer",
|
|
2181
|
+
"credential_type"
|
|
2182
|
+
]
|
|
2183
|
+
});
|
|
2184
|
+
credentialOffer = {
|
|
2185
|
+
credential_offer: credentialOfferPayload
|
|
2186
|
+
};
|
|
2187
|
+
} else {
|
|
2188
|
+
if (uri.includes("credential_offer_uri")) {
|
|
2189
|
+
credentialOffer = await handleCredentialOfferUri(uri);
|
|
2190
|
+
} else {
|
|
2191
|
+
credentialOffer = (0, import_oid4vci_common16.convertURIToJsonObject)(uri, {
|
|
2192
|
+
// It must have the '=' sign after credential_offer otherwise the uri will get split at openid_credential_offer
|
|
2193
|
+
arrayTypeProperties: uri.includes("credential_offer_uri=") ? [
|
|
2194
|
+
"credential_offer_uri="
|
|
2195
|
+
] : [
|
|
2196
|
+
"credential_offer="
|
|
2197
|
+
],
|
|
2198
|
+
requiredProperties: uri.includes("credential_offer_uri=") ? [
|
|
2199
|
+
"credential_offer_uri="
|
|
2200
|
+
] : [
|
|
2201
|
+
"credential_offer="
|
|
2202
|
+
]
|
|
2203
|
+
});
|
|
2204
|
+
}
|
|
2205
|
+
if (credentialOffer?.credential_offer_uri === void 0 && !credentialOffer?.credential_offer) {
|
|
2206
|
+
throw Error("Either a credential_offer or credential_offer_uri should be present in " + uri);
|
|
2207
|
+
}
|
|
2208
|
+
}
|
|
2209
|
+
const request = await (0, import_oid4vci_common16.toUniformCredentialOfferRequest)(credentialOffer, {
|
|
2210
|
+
...opts,
|
|
2211
|
+
version
|
|
2212
|
+
});
|
|
2213
|
+
return {
|
|
2214
|
+
...constructBaseResponse(request, scheme, baseUrl),
|
|
2215
|
+
userPinRequired: request.credential_offer?.grants?.[import_oid4vci_common16.PRE_AUTH_GRANT_LITERAL]?.user_pin_required ?? !!request.credential_offer?.grants?.[import_oid4vci_common16.PRE_AUTH_GRANT_LITERAL]?.tx_code ?? false
|
|
2216
|
+
};
|
|
2217
|
+
}
|
|
2218
|
+
static toURI(requestWithBaseUrl, opts) {
|
|
2219
|
+
debug9(`Credential Offer Request with base URL: ${JSON.stringify(requestWithBaseUrl)}`);
|
|
2220
|
+
const version = opts?.version ?? requestWithBaseUrl.version;
|
|
2221
|
+
let baseUrl = requestWithBaseUrl.baseUrl.includes(requestWithBaseUrl.scheme) ? requestWithBaseUrl.baseUrl : `${requestWithBaseUrl.scheme.replace("://", "")}://${requestWithBaseUrl.baseUrl}`;
|
|
2222
|
+
let param;
|
|
2223
|
+
const isUri = requestWithBaseUrl.credential_offer_uri !== void 0;
|
|
2224
|
+
if (version.valueOf() >= import_oid4vci_common16.OpenId4VCIVersion.VER_1_0_11.valueOf()) {
|
|
2225
|
+
if (!baseUrl.includes("?")) {
|
|
2226
|
+
param = isUri ? "credential_offer_uri" : "credential_offer";
|
|
2227
|
+
} else {
|
|
2228
|
+
const split = baseUrl.split("?");
|
|
2229
|
+
if (split.length > 1 && split[1] !== "") {
|
|
2230
|
+
if (baseUrl.endsWith("&")) {
|
|
2231
|
+
param = isUri ? "credential_offer_uri" : "credential_offer";
|
|
2232
|
+
} else if (!baseUrl.endsWith("=")) {
|
|
2233
|
+
baseUrl += `&`;
|
|
2234
|
+
param = isUri ? "credential_offer_uri" : "credential_offer";
|
|
2235
|
+
}
|
|
2236
|
+
}
|
|
2237
|
+
}
|
|
2238
|
+
}
|
|
2239
|
+
return (0, import_oid4vci_common16.convertJsonToURI)(requestWithBaseUrl.credential_offer_uri ?? requestWithBaseUrl.original_credential_offer, {
|
|
2240
|
+
baseUrl,
|
|
2241
|
+
arrayTypeProperties: isUri ? [] : [
|
|
2242
|
+
"credential_type"
|
|
2243
|
+
],
|
|
2244
|
+
uriTypeProperties: isUri ? [
|
|
2245
|
+
"credential_offer_uri"
|
|
2246
|
+
] : version >= import_oid4vci_common16.OpenId4VCIVersion.VER_1_0_13 ? [
|
|
2247
|
+
"credential_issuer",
|
|
2248
|
+
"credential_type"
|
|
2249
|
+
] : [
|
|
2250
|
+
"issuer",
|
|
2251
|
+
"credential_type"
|
|
2252
|
+
],
|
|
2253
|
+
param,
|
|
2254
|
+
version
|
|
2255
|
+
});
|
|
2256
|
+
}
|
|
2257
|
+
};
|
|
2258
|
+
|
|
2259
|
+
// lib/CredentialOfferClientV1_0_11.ts
|
|
2260
|
+
var import_oid4vci_common17 = require("@sphereon/oid4vci-common");
|
|
2261
|
+
var import_debug10 = __toESM(require("debug"), 1);
|
|
2262
|
+
var debug10 = (0, import_debug10.default)("sphereon:oid4vci:offer");
|
|
2263
|
+
var CredentialOfferClientV1_0_11 = class {
|
|
2264
|
+
static {
|
|
2265
|
+
__name(this, "CredentialOfferClientV1_0_11");
|
|
2266
|
+
}
|
|
2267
|
+
static async fromURI(uri, opts) {
|
|
2268
|
+
debug10(`Credential Offer URI: ${uri}`);
|
|
2269
|
+
if (!uri.includes("?") || !uri.includes("://")) {
|
|
2270
|
+
debug10(`Invalid Credential Offer URI: ${uri}`);
|
|
2271
|
+
throw Error(`Invalid Credential Offer Request`);
|
|
2272
|
+
}
|
|
2273
|
+
const scheme = uri.split("://")[0];
|
|
2274
|
+
const baseUrl = uri.split("?")[0];
|
|
2275
|
+
const version = (0, import_oid4vci_common17.determineSpecVersionFromURI)(uri);
|
|
2276
|
+
let credentialOffer;
|
|
2277
|
+
let credentialOfferPayload;
|
|
2278
|
+
if (version < import_oid4vci_common17.OpenId4VCIVersion.VER_1_0_11) {
|
|
2279
|
+
credentialOfferPayload = (0, import_oid4vci_common17.convertURIToJsonObject)(uri, {
|
|
2280
|
+
arrayTypeProperties: [
|
|
2281
|
+
"credential_type"
|
|
2282
|
+
],
|
|
2283
|
+
requiredProperties: uri.includes("credential_offer_uri=") ? [
|
|
2284
|
+
"credential_offer_uri="
|
|
2285
|
+
] : [
|
|
2286
|
+
"issuer",
|
|
2287
|
+
"credential_type="
|
|
2288
|
+
]
|
|
2289
|
+
});
|
|
2290
|
+
credentialOffer = {
|
|
2291
|
+
credential_offer: credentialOfferPayload
|
|
2292
|
+
};
|
|
2293
|
+
} else {
|
|
2294
|
+
credentialOffer = (0, import_oid4vci_common17.convertURIToJsonObject)(uri, {
|
|
2295
|
+
arrayTypeProperties: [
|
|
2296
|
+
"credentials"
|
|
2297
|
+
],
|
|
2298
|
+
requiredProperties: uri.includes("credential_offer_uri=") ? [
|
|
2299
|
+
"credential_offer_uri="
|
|
2300
|
+
] : [
|
|
2301
|
+
"credential_offer="
|
|
2302
|
+
]
|
|
2303
|
+
});
|
|
2304
|
+
if (credentialOffer?.credential_offer_uri === void 0 && !credentialOffer?.credential_offer) {
|
|
2305
|
+
throw Error("Either a credential_offer or credential_offer_uri should be present in " + uri);
|
|
2306
|
+
}
|
|
2307
|
+
}
|
|
2308
|
+
const request = await (0, import_oid4vci_common17.toUniformCredentialOfferRequest)(credentialOffer, {
|
|
2309
|
+
...opts,
|
|
2310
|
+
version
|
|
2311
|
+
});
|
|
2312
|
+
const clientId = (0, import_oid4vci_common17.getClientIdFromCredentialOfferPayload)(request.credential_offer);
|
|
2313
|
+
const grants = request.credential_offer?.grants;
|
|
2314
|
+
return {
|
|
2315
|
+
scheme,
|
|
2316
|
+
baseUrl,
|
|
2317
|
+
...clientId && {
|
|
2318
|
+
clientId
|
|
2319
|
+
},
|
|
2320
|
+
...request,
|
|
2321
|
+
...grants?.authorization_code?.issuer_state && {
|
|
2322
|
+
issuerState: grants.authorization_code.issuer_state
|
|
2323
|
+
},
|
|
2324
|
+
...grants?.[import_oid4vci_common17.PRE_AUTH_GRANT_LITERAL]?.[import_oid4vci_common17.PRE_AUTH_CODE_LITERAL] && {
|
|
2325
|
+
preAuthorizedCode: grants[import_oid4vci_common17.PRE_AUTH_GRANT_LITERAL][import_oid4vci_common17.PRE_AUTH_CODE_LITERAL]
|
|
2326
|
+
},
|
|
2327
|
+
userPinRequired: !!(request.credential_offer?.grants?.[import_oid4vci_common17.PRE_AUTH_GRANT_LITERAL]?.user_pin_required ?? false)
|
|
2328
|
+
};
|
|
2329
|
+
}
|
|
2330
|
+
static toURI(requestWithBaseUrl, opts) {
|
|
2331
|
+
debug10(`Credential Offer Request with base URL: ${JSON.stringify(requestWithBaseUrl)}`);
|
|
2332
|
+
const version = opts?.version ?? requestWithBaseUrl.version;
|
|
2333
|
+
let baseUrl = requestWithBaseUrl.baseUrl.includes(requestWithBaseUrl.scheme) ? requestWithBaseUrl.baseUrl : `${requestWithBaseUrl.scheme.replace("://", "")}://${requestWithBaseUrl.baseUrl}`;
|
|
2334
|
+
let param;
|
|
2335
|
+
const isUri = requestWithBaseUrl.credential_offer_uri !== void 0;
|
|
2336
|
+
if (version.valueOf() >= import_oid4vci_common17.OpenId4VCIVersion.VER_1_0_11.valueOf()) {
|
|
2337
|
+
if (!baseUrl.includes("?")) {
|
|
2338
|
+
param = isUri ? "credential_offer_uri" : "credential_offer";
|
|
2339
|
+
} else {
|
|
2340
|
+
const split = baseUrl.split("?");
|
|
2341
|
+
if (split.length > 1 && split[1] !== "") {
|
|
2342
|
+
if (baseUrl.endsWith("&")) {
|
|
2343
|
+
param = isUri ? "credential_offer_uri" : "credential_offer";
|
|
2344
|
+
} else if (!baseUrl.endsWith("=")) {
|
|
2345
|
+
baseUrl += `&`;
|
|
2346
|
+
param = isUri ? "credential_offer_uri" : "credential_offer";
|
|
2347
|
+
}
|
|
2348
|
+
}
|
|
2349
|
+
}
|
|
2350
|
+
}
|
|
2351
|
+
return (0, import_oid4vci_common17.convertJsonToURI)(requestWithBaseUrl.credential_offer_uri ?? requestWithBaseUrl.original_credential_offer, {
|
|
2352
|
+
baseUrl,
|
|
2353
|
+
arrayTypeProperties: isUri ? [] : [
|
|
2354
|
+
"credential_type"
|
|
2355
|
+
],
|
|
2356
|
+
uriTypeProperties: isUri ? [
|
|
2357
|
+
"credential_offer_uri"
|
|
2358
|
+
] : version >= import_oid4vci_common17.OpenId4VCIVersion.VER_1_0_11 ? [
|
|
2359
|
+
"credential_issuer",
|
|
2360
|
+
"credential_type"
|
|
2361
|
+
] : [
|
|
2362
|
+
"issuer",
|
|
2363
|
+
"credential_type"
|
|
2364
|
+
],
|
|
2365
|
+
param,
|
|
2366
|
+
version
|
|
2367
|
+
});
|
|
2368
|
+
}
|
|
2369
|
+
};
|
|
2370
|
+
|
|
2371
|
+
// lib/CredentialOfferClientV1_0_13.ts
|
|
2372
|
+
var import_oid4vci_common18 = require("@sphereon/oid4vci-common");
|
|
2373
|
+
var import_debug11 = __toESM(require("debug"), 1);
|
|
2374
|
+
var debug11 = (0, import_debug11.default)("sphereon:oid4vci:offer");
|
|
2375
|
+
var CredentialOfferClientV1_0_13 = class {
|
|
2376
|
+
static {
|
|
2377
|
+
__name(this, "CredentialOfferClientV1_0_13");
|
|
2378
|
+
}
|
|
2379
|
+
static async fromURI(uri, opts) {
|
|
2380
|
+
debug11(`Credential Offer URI: ${uri}`);
|
|
2381
|
+
if (!uri.includes("?") || !uri.includes("://")) {
|
|
2382
|
+
debug11(`Invalid Credential Offer URI: ${uri}`);
|
|
2383
|
+
throw Error(`Invalid Credential Offer Request`);
|
|
2384
|
+
}
|
|
2385
|
+
const scheme = uri.split("://")[0];
|
|
2386
|
+
const baseUrl = uri.split("?")[0];
|
|
2387
|
+
const version = (0, import_oid4vci_common18.determineSpecVersionFromURI)(uri);
|
|
2388
|
+
let credentialOffer;
|
|
2389
|
+
if (uri.includes("credential_offer_uri")) {
|
|
2390
|
+
credentialOffer = await handleCredentialOfferUri(uri);
|
|
2391
|
+
} else {
|
|
2392
|
+
credentialOffer = (0, import_oid4vci_common18.convertURIToJsonObject)(uri, {
|
|
2393
|
+
// It must have the '=' sign after credential_offer otherwise the uri will get split at openid_credential_offer
|
|
2394
|
+
arrayTypeProperties: uri.includes("credential_offer_uri=") ? [
|
|
2395
|
+
"credential_configuration_ids",
|
|
2396
|
+
"credential_offer_uri="
|
|
2397
|
+
] : [
|
|
2398
|
+
"credential_configuration_ids",
|
|
2399
|
+
"credential_offer="
|
|
2400
|
+
],
|
|
2401
|
+
requiredProperties: uri.includes("credential_offer_uri=") ? [
|
|
2402
|
+
"credential_offer_uri="
|
|
2403
|
+
] : [
|
|
2404
|
+
"credential_offer="
|
|
2405
|
+
]
|
|
2406
|
+
});
|
|
2407
|
+
}
|
|
2408
|
+
if (credentialOffer?.credential_offer_uri === void 0 && !credentialOffer?.credential_offer) {
|
|
2409
|
+
throw Error("Either a credential_offer or credential_offer_uri should be present in " + uri);
|
|
2410
|
+
}
|
|
2411
|
+
const request = await (0, import_oid4vci_common18.toUniformCredentialOfferRequest)(credentialOffer, {
|
|
2412
|
+
...opts,
|
|
2413
|
+
version
|
|
2414
|
+
});
|
|
2415
|
+
return {
|
|
2416
|
+
...constructBaseResponse(request, scheme, baseUrl),
|
|
2417
|
+
userPinRequired: !!(request.credential_offer?.grants?.[import_oid4vci_common18.PRE_AUTH_GRANT_LITERAL]?.tx_code ?? false)
|
|
2418
|
+
};
|
|
2419
|
+
}
|
|
2420
|
+
static toURI(requestWithBaseUrl, opts) {
|
|
2421
|
+
debug11(`Credential Offer Request with base URL: ${JSON.stringify(requestWithBaseUrl)}`);
|
|
2422
|
+
const version = opts?.version ?? requestWithBaseUrl.version;
|
|
2423
|
+
let baseUrl = requestWithBaseUrl.baseUrl.includes(requestWithBaseUrl.scheme) ? requestWithBaseUrl.baseUrl : `${requestWithBaseUrl.scheme.replace("://", "")}://${requestWithBaseUrl.baseUrl}`;
|
|
2424
|
+
let param;
|
|
2425
|
+
const isUri = requestWithBaseUrl.credential_offer_uri !== void 0;
|
|
2426
|
+
if (version.valueOf() >= import_oid4vci_common18.OpenId4VCIVersion.VER_1_0_11.valueOf()) {
|
|
2427
|
+
if (!baseUrl.includes("?")) {
|
|
2428
|
+
param = isUri ? "credential_offer_uri" : "credential_offer";
|
|
2429
|
+
} else {
|
|
2430
|
+
const split = baseUrl.split("?");
|
|
2431
|
+
if (split.length > 1 && split[1] !== "") {
|
|
2432
|
+
if (baseUrl.endsWith("&")) {
|
|
2433
|
+
param = isUri ? "credential_offer_uri" : "credential_offer";
|
|
2434
|
+
} else if (!baseUrl.endsWith("=")) {
|
|
2435
|
+
baseUrl += `&`;
|
|
2436
|
+
param = isUri ? "credential_offer_uri" : "credential_offer";
|
|
2437
|
+
}
|
|
2438
|
+
}
|
|
2439
|
+
}
|
|
2440
|
+
}
|
|
2441
|
+
return (0, import_oid4vci_common18.convertJsonToURI)(requestWithBaseUrl.credential_offer_uri ?? requestWithBaseUrl.original_credential_offer, {
|
|
2442
|
+
baseUrl,
|
|
2443
|
+
arrayTypeProperties: isUri ? [] : [
|
|
2444
|
+
"credential_type"
|
|
2445
|
+
],
|
|
2446
|
+
uriTypeProperties: isUri ? [
|
|
2447
|
+
"credential_offer_uri"
|
|
2448
|
+
] : version >= import_oid4vci_common18.OpenId4VCIVersion.VER_1_0_13 ? [
|
|
2449
|
+
"credential_issuer",
|
|
2450
|
+
"credential_type"
|
|
2451
|
+
] : [
|
|
2452
|
+
"issuer",
|
|
2453
|
+
"credential_type"
|
|
2454
|
+
],
|
|
2455
|
+
param,
|
|
2456
|
+
version
|
|
2457
|
+
});
|
|
2458
|
+
}
|
|
2459
|
+
};
|
|
2460
|
+
|
|
2461
|
+
// lib/CredentialRequestClientV1_0_11.ts
|
|
2462
|
+
var import_oid4vc_common6 = require("@sphereon/oid4vc-common");
|
|
2463
|
+
var import_oid4vci_common19 = require("@sphereon/oid4vci-common");
|
|
2464
|
+
var import_debug12 = __toESM(require("debug"), 1);
|
|
2465
|
+
var debug12 = (0, import_debug12.default)("sphereon:oid4vci:credential");
|
|
2466
|
+
var CredentialRequestClientV1_0_11 = class {
|
|
2467
|
+
static {
|
|
2468
|
+
__name(this, "CredentialRequestClientV1_0_11");
|
|
2469
|
+
}
|
|
2470
|
+
_credentialRequestOpts;
|
|
2471
|
+
_isDeferred = false;
|
|
2472
|
+
get credentialRequestOpts() {
|
|
2473
|
+
return this._credentialRequestOpts;
|
|
2474
|
+
}
|
|
2475
|
+
isDeferred() {
|
|
2476
|
+
return this._isDeferred;
|
|
2477
|
+
}
|
|
2478
|
+
getCredentialEndpoint() {
|
|
2479
|
+
return this.credentialRequestOpts.credentialEndpoint;
|
|
2480
|
+
}
|
|
2481
|
+
getDeferredCredentialEndpoint() {
|
|
2482
|
+
return this.credentialRequestOpts.deferredCredentialEndpoint;
|
|
2483
|
+
}
|
|
2484
|
+
constructor(builder) {
|
|
2485
|
+
this._credentialRequestOpts = {
|
|
2486
|
+
...builder
|
|
2487
|
+
};
|
|
2488
|
+
}
|
|
2489
|
+
async acquireCredentialsUsingProof(opts) {
|
|
2490
|
+
const { credentialTypes, proofInput, format, context } = opts;
|
|
2491
|
+
const request = await this.createCredentialRequest({
|
|
2492
|
+
proofInput,
|
|
2493
|
+
credentialTypes,
|
|
2494
|
+
context,
|
|
2495
|
+
format,
|
|
2496
|
+
version: this.version()
|
|
2497
|
+
});
|
|
2498
|
+
return await this.acquireCredentialsUsingRequest(request, opts.createDPoPOpts);
|
|
2499
|
+
}
|
|
2500
|
+
async acquireCredentialsUsingRequest(uniformRequest, createDPoPOpts) {
|
|
2501
|
+
const request = (0, import_oid4vci_common19.getCredentialRequestForVersion)(uniformRequest, this.version());
|
|
2502
|
+
const credentialEndpoint = this.credentialRequestOpts.credentialEndpoint;
|
|
2503
|
+
if (!(0, import_oid4vci_common19.isValidURL)(credentialEndpoint)) {
|
|
2504
|
+
debug12(`Invalid credential endpoint: ${credentialEndpoint}`);
|
|
2505
|
+
throw new Error(import_oid4vci_common19.URL_NOT_VALID);
|
|
2506
|
+
}
|
|
2507
|
+
debug12(`Acquiring credential(s) from: ${credentialEndpoint}`);
|
|
2508
|
+
debug12(`request
|
|
2509
|
+
: ${JSON.stringify(request, null, 2)}`);
|
|
2510
|
+
const requestToken = this.credentialRequestOpts.token;
|
|
2511
|
+
let dPoP = createDPoPOpts ? await (0, import_oid4vc_common6.createDPoP)((0, import_oid4vc_common6.getCreateDPoPOptions)(createDPoPOpts, credentialEndpoint, {
|
|
2512
|
+
accessToken: requestToken
|
|
2513
|
+
})) : void 0;
|
|
2514
|
+
let response = await (0, import_oid4vci_common19.post)(credentialEndpoint, JSON.stringify(request), {
|
|
2515
|
+
bearerToken: requestToken,
|
|
2516
|
+
customHeaders: {
|
|
2517
|
+
...createDPoPOpts && {
|
|
2518
|
+
dpop: dPoP
|
|
2519
|
+
}
|
|
2520
|
+
}
|
|
2521
|
+
});
|
|
2522
|
+
let nextDPoPNonce = createDPoPOpts?.jwtPayloadProps.nonce;
|
|
2523
|
+
const retryWithNonce = shouldRetryResourceRequestWithDPoPNonce(response);
|
|
2524
|
+
if (retryWithNonce.ok && createDPoPOpts) {
|
|
2525
|
+
createDPoPOpts.jwtPayloadProps.nonce = retryWithNonce.dpopNonce;
|
|
2526
|
+
dPoP = await (0, import_oid4vc_common6.createDPoP)((0, import_oid4vc_common6.getCreateDPoPOptions)(createDPoPOpts, credentialEndpoint, {
|
|
2527
|
+
accessToken: requestToken
|
|
2528
|
+
}));
|
|
2529
|
+
response = await (0, import_oid4vci_common19.post)(credentialEndpoint, JSON.stringify(request), {
|
|
2530
|
+
bearerToken: requestToken,
|
|
2531
|
+
customHeaders: {
|
|
2532
|
+
...createDPoPOpts && {
|
|
2533
|
+
dpop: dPoP
|
|
2534
|
+
}
|
|
2535
|
+
}
|
|
2536
|
+
});
|
|
2537
|
+
const successDPoPNonce = response.origResponse.headers.get("DPoP-Nonce");
|
|
2538
|
+
nextDPoPNonce = successDPoPNonce ?? retryWithNonce.dpopNonce;
|
|
2539
|
+
}
|
|
2540
|
+
this._isDeferred = (0, import_oid4vci_common19.isDeferredCredentialResponse)(response);
|
|
2541
|
+
if (this.isDeferred() && this.credentialRequestOpts.deferredCredentialAwait && response.successBody) {
|
|
2542
|
+
response = await this.acquireDeferredCredential(response.successBody, {
|
|
2543
|
+
bearerToken: this.credentialRequestOpts.token
|
|
2544
|
+
});
|
|
2545
|
+
}
|
|
2546
|
+
response.access_token = requestToken;
|
|
2547
|
+
debug12(`Credential endpoint ${credentialEndpoint} response:\r
|
|
2548
|
+
${JSON.stringify(response, null, 2)}`);
|
|
2549
|
+
return {
|
|
2550
|
+
...response,
|
|
2551
|
+
...nextDPoPNonce && {
|
|
2552
|
+
params: {
|
|
2553
|
+
dpop: {
|
|
2554
|
+
dpopNonce: nextDPoPNonce
|
|
2555
|
+
}
|
|
2556
|
+
}
|
|
2557
|
+
}
|
|
2558
|
+
};
|
|
2559
|
+
}
|
|
2560
|
+
async acquireDeferredCredential(response, opts) {
|
|
2561
|
+
const transactionId = response.transaction_id;
|
|
2562
|
+
const bearerToken = response.acceptance_token ?? opts?.bearerToken;
|
|
2563
|
+
const deferredCredentialEndpoint = this.getDeferredCredentialEndpoint();
|
|
2564
|
+
if (!deferredCredentialEndpoint) {
|
|
2565
|
+
throw Error(`No deferred credential endpoint supplied.`);
|
|
2566
|
+
} else if (!bearerToken) {
|
|
2567
|
+
throw Error(`No bearer token present and refresh for defered endpoint not supported yet`);
|
|
2568
|
+
}
|
|
2569
|
+
return await (0, import_oid4vci_common19.acquireDeferredCredential)({
|
|
2570
|
+
bearerToken,
|
|
2571
|
+
transactionId,
|
|
2572
|
+
deferredCredentialEndpoint,
|
|
2573
|
+
deferredCredentialAwait: this.credentialRequestOpts.deferredCredentialAwait,
|
|
2574
|
+
deferredCredentialIntervalInMS: this.credentialRequestOpts.deferredCredentialIntervalInMS
|
|
2575
|
+
});
|
|
2576
|
+
}
|
|
2577
|
+
async createCredentialRequest(opts) {
|
|
2578
|
+
const { proofInput } = opts;
|
|
2579
|
+
const formatSelection = opts.format ?? this.credentialRequestOpts.format;
|
|
2580
|
+
if (!formatSelection) {
|
|
2581
|
+
throw Error(`Format of credential to be issued is missing`);
|
|
2582
|
+
}
|
|
2583
|
+
const format = (0, import_oid4vci_common19.getUniformFormat)(formatSelection);
|
|
2584
|
+
const typesSelection = opts?.credentialTypes && (typeof opts.credentialTypes === "string" || opts.credentialTypes.length > 0) ? opts.credentialTypes : this.credentialRequestOpts.credentialTypes;
|
|
2585
|
+
const types = Array.isArray(typesSelection) ? typesSelection : [
|
|
2586
|
+
typesSelection
|
|
2587
|
+
];
|
|
2588
|
+
if (types.length === 0) {
|
|
2589
|
+
throw Error(`Credential type(s) need to be provided`);
|
|
2590
|
+
} else if (!this.isV11OrHigher() && types.length !== 1) {
|
|
2591
|
+
throw Error("Only a single credential type is supported for V8/V9");
|
|
2592
|
+
}
|
|
2593
|
+
const proof = await buildProof(proofInput, opts);
|
|
2594
|
+
if (format === "jwt_vc_json" || format === "jwt_vc") {
|
|
2595
|
+
return {
|
|
2596
|
+
types,
|
|
2597
|
+
format,
|
|
2598
|
+
proof
|
|
2599
|
+
};
|
|
2600
|
+
} else if (format === "jwt_vc_json-ld" || format === "ldp_vc") {
|
|
2601
|
+
if (this.version() >= import_oid4vci_common19.OpenId4VCIVersion.VER_1_0_12 && !opts.context) {
|
|
2602
|
+
throw Error("No @context value present, but it is required");
|
|
2603
|
+
}
|
|
2604
|
+
return {
|
|
2605
|
+
format,
|
|
2606
|
+
proof,
|
|
2607
|
+
// Ignored because v11 does not have the context value, but it is required in v12
|
|
2608
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
2609
|
+
// @ts-ignore
|
|
2610
|
+
credential_definition: {
|
|
2611
|
+
types,
|
|
2612
|
+
...opts.context && {
|
|
2613
|
+
"@context": opts.context
|
|
2614
|
+
}
|
|
2615
|
+
}
|
|
2616
|
+
};
|
|
2617
|
+
} else if (format === "vc+sd-jwt") {
|
|
2618
|
+
if (types.length > 1) {
|
|
2619
|
+
throw Error(`Only a single credential type is supported for ${format}`);
|
|
2620
|
+
}
|
|
2621
|
+
return {
|
|
2622
|
+
format,
|
|
2623
|
+
proof,
|
|
2624
|
+
vct: types[0]
|
|
2625
|
+
};
|
|
2626
|
+
} else if (format === "mso_mdoc") {
|
|
2627
|
+
if (types.length > 1) {
|
|
2628
|
+
throw Error(`Only a single credential type is supported for ${format}`);
|
|
2629
|
+
}
|
|
2630
|
+
return {
|
|
2631
|
+
format,
|
|
2632
|
+
proof,
|
|
2633
|
+
doctype: types[0]
|
|
2634
|
+
};
|
|
2635
|
+
}
|
|
2636
|
+
throw new Error(`Unsupported format: ${format}`);
|
|
2637
|
+
}
|
|
2638
|
+
version() {
|
|
2639
|
+
return this.credentialRequestOpts?.version ?? import_oid4vci_common19.OpenId4VCIVersion.VER_1_0_11;
|
|
2640
|
+
}
|
|
2641
|
+
isV11OrHigher() {
|
|
2642
|
+
return this.version() >= import_oid4vci_common19.OpenId4VCIVersion.VER_1_0_11;
|
|
2643
|
+
}
|
|
2644
|
+
};
|
|
2645
|
+
|
|
2646
|
+
// lib/CredentialRequestClientBuilder.ts
|
|
2647
|
+
var import_oid4vci_common22 = require("@sphereon/oid4vci-common");
|
|
2648
|
+
|
|
2649
|
+
// lib/CredentialRequestClientBuilderV1_0_11.ts
|
|
2650
|
+
var import_oid4vci_common20 = require("@sphereon/oid4vci-common");
|
|
2651
|
+
var CredentialRequestClientBuilderV1_0_11 = class _CredentialRequestClientBuilderV1_0_11 {
|
|
2652
|
+
static {
|
|
2653
|
+
__name(this, "CredentialRequestClientBuilderV1_0_11");
|
|
2654
|
+
}
|
|
2655
|
+
credentialEndpoint;
|
|
2656
|
+
deferredCredentialEndpoint;
|
|
2657
|
+
deferredCredentialAwait = false;
|
|
2658
|
+
deferredCredentialIntervalInMS = 5e3;
|
|
2659
|
+
credentialTypes = [];
|
|
2660
|
+
format;
|
|
2661
|
+
token;
|
|
2662
|
+
version;
|
|
2663
|
+
subjectIssuance;
|
|
2664
|
+
issuerState;
|
|
2665
|
+
static fromCredentialIssuer({ credentialIssuer, metadata, version, credentialTypes }) {
|
|
2666
|
+
const issuer = credentialIssuer;
|
|
2667
|
+
const builder = new _CredentialRequestClientBuilderV1_0_11();
|
|
2668
|
+
builder.withVersion(version ?? import_oid4vci_common20.OpenId4VCIVersion.VER_1_0_11);
|
|
2669
|
+
builder.withCredentialEndpoint(metadata?.credential_endpoint ?? (issuer.endsWith("/") ? `${issuer}credential` : `${issuer}/credential`));
|
|
2670
|
+
if (metadata?.deferred_credential_endpoint) {
|
|
2671
|
+
builder.withDeferredCredentialEndpoint(metadata.deferred_credential_endpoint);
|
|
2672
|
+
}
|
|
2673
|
+
builder.withCredentialType(credentialTypes);
|
|
2674
|
+
return builder;
|
|
2675
|
+
}
|
|
2676
|
+
static async fromURI({ uri, metadata }) {
|
|
2677
|
+
const offer = await CredentialOfferClientV1_0_11.fromURI(uri);
|
|
2678
|
+
return _CredentialRequestClientBuilderV1_0_11.fromCredentialOfferRequest({
|
|
2679
|
+
request: offer,
|
|
2680
|
+
...offer,
|
|
2681
|
+
metadata,
|
|
2682
|
+
version: offer.version
|
|
2683
|
+
});
|
|
2684
|
+
}
|
|
2685
|
+
static fromCredentialOfferRequest(opts) {
|
|
2686
|
+
const { request, metadata } = opts;
|
|
2687
|
+
const version = opts.version ?? request.version ?? (0, import_oid4vci_common20.determineSpecVersionFromOffer)(request.original_credential_offer);
|
|
2688
|
+
const builder = new _CredentialRequestClientBuilderV1_0_11();
|
|
2689
|
+
const issuer = (0, import_oid4vci_common20.getIssuerFromCredentialOfferPayload)(request.credential_offer) ?? metadata?.issuer;
|
|
2690
|
+
builder.withVersion(version);
|
|
2691
|
+
builder.withCredentialEndpoint(metadata?.credential_endpoint ?? (issuer.endsWith("/") ? `${issuer}credential` : `${issuer}/credential`));
|
|
2692
|
+
if (metadata?.deferred_credential_endpoint) {
|
|
2693
|
+
builder.withDeferredCredentialEndpoint(metadata.deferred_credential_endpoint);
|
|
2694
|
+
}
|
|
2695
|
+
if (version <= import_oid4vci_common20.OpenId4VCIVersion.VER_1_0_08) {
|
|
2696
|
+
builder.withCredentialType(request.original_credential_offer.credential_type);
|
|
2697
|
+
} else if (version <= import_oid4vci_common20.OpenId4VCIVersion.VER_1_0_11) {
|
|
2698
|
+
builder.withCredentialType((0, import_oid4vci_common20.getTypesFromOfferV1_0_11)(request.credential_offer));
|
|
2699
|
+
}
|
|
2700
|
+
return builder;
|
|
2701
|
+
}
|
|
2702
|
+
static fromCredentialOffer({ credentialOffer, metadata }) {
|
|
2703
|
+
return _CredentialRequestClientBuilderV1_0_11.fromCredentialOfferRequest({
|
|
2704
|
+
request: credentialOffer,
|
|
2705
|
+
metadata,
|
|
2706
|
+
version: credentialOffer.version
|
|
2707
|
+
});
|
|
2708
|
+
}
|
|
2709
|
+
withIssuerState(issuerState) {
|
|
2710
|
+
this.issuerState = issuerState;
|
|
2711
|
+
return this;
|
|
2712
|
+
}
|
|
2713
|
+
withCredentialEndpointFromMetadata(metadata) {
|
|
2714
|
+
this.credentialEndpoint = metadata.credential_endpoint;
|
|
2715
|
+
return this;
|
|
2716
|
+
}
|
|
2717
|
+
withCredentialEndpoint(credentialEndpoint) {
|
|
2718
|
+
this.credentialEndpoint = credentialEndpoint;
|
|
2719
|
+
return this;
|
|
2720
|
+
}
|
|
2721
|
+
withDeferredCredentialEndpointFromMetadata(metadata) {
|
|
2722
|
+
this.deferredCredentialEndpoint = metadata.deferred_credential_endpoint;
|
|
2723
|
+
return this;
|
|
2724
|
+
}
|
|
2725
|
+
withDeferredCredentialEndpoint(deferredCredentialEndpoint) {
|
|
2726
|
+
this.deferredCredentialEndpoint = deferredCredentialEndpoint;
|
|
2727
|
+
return this;
|
|
2728
|
+
}
|
|
2729
|
+
withDeferredCredentialAwait(deferredCredentialAwait, deferredCredentialIntervalInMS) {
|
|
2730
|
+
this.deferredCredentialAwait = deferredCredentialAwait;
|
|
2731
|
+
this.deferredCredentialIntervalInMS = deferredCredentialIntervalInMS ?? 5e3;
|
|
2732
|
+
return this;
|
|
2733
|
+
}
|
|
2734
|
+
withCredentialType(credentialTypes) {
|
|
2735
|
+
this.credentialTypes = Array.isArray(credentialTypes) ? credentialTypes : [
|
|
2736
|
+
credentialTypes
|
|
2737
|
+
];
|
|
2738
|
+
return this;
|
|
2739
|
+
}
|
|
2740
|
+
withFormat(format) {
|
|
2741
|
+
this.format = format;
|
|
2742
|
+
return this;
|
|
2743
|
+
}
|
|
2744
|
+
withSubjectIssuance(subjectIssuance) {
|
|
2745
|
+
this.subjectIssuance = subjectIssuance;
|
|
2746
|
+
return this;
|
|
2747
|
+
}
|
|
2748
|
+
withToken(accessToken) {
|
|
2749
|
+
this.token = accessToken;
|
|
2750
|
+
return this;
|
|
2751
|
+
}
|
|
2752
|
+
withTokenFromResponse(response) {
|
|
2753
|
+
this.token = response.access_token;
|
|
2754
|
+
return this;
|
|
2755
|
+
}
|
|
2756
|
+
withVersion(version) {
|
|
2757
|
+
this.version = version;
|
|
2758
|
+
return this;
|
|
2759
|
+
}
|
|
2760
|
+
build() {
|
|
2761
|
+
if (!this.version) {
|
|
2762
|
+
this.withVersion(import_oid4vci_common20.OpenId4VCIVersion.VER_1_0_11);
|
|
2763
|
+
}
|
|
2764
|
+
return new CredentialRequestClientV1_0_11(this);
|
|
2765
|
+
}
|
|
2766
|
+
};
|
|
2767
|
+
|
|
2768
|
+
// lib/CredentialRequestClientBuilderV1_0_13.ts
|
|
2769
|
+
var import_oid4vci_common21 = require("@sphereon/oid4vci-common");
|
|
2770
|
+
var CredentialRequestClientBuilderV1_0_13 = class _CredentialRequestClientBuilderV1_0_13 {
|
|
2771
|
+
static {
|
|
2772
|
+
__name(this, "CredentialRequestClientBuilderV1_0_13");
|
|
2773
|
+
}
|
|
2774
|
+
credentialEndpoint;
|
|
2775
|
+
deferredCredentialEndpoint;
|
|
2776
|
+
deferredCredentialAwait = false;
|
|
2777
|
+
deferredCredentialIntervalInMS = 5e3;
|
|
2778
|
+
credentialIdentifier;
|
|
2779
|
+
credentialTypes = [];
|
|
2780
|
+
format;
|
|
2781
|
+
token;
|
|
2782
|
+
version;
|
|
2783
|
+
subjectIssuance;
|
|
2784
|
+
issuerState;
|
|
2785
|
+
static fromCredentialIssuer({ credentialIssuer, metadata, version, credentialIdentifier, credentialTypes }) {
|
|
2786
|
+
const issuer = credentialIssuer;
|
|
2787
|
+
const builder = new _CredentialRequestClientBuilderV1_0_13();
|
|
2788
|
+
builder.withVersion(version ?? import_oid4vci_common21.OpenId4VCIVersion.VER_1_0_13);
|
|
2789
|
+
builder.withCredentialEndpoint(metadata?.credential_endpoint ?? (issuer.endsWith("/") ? `${issuer}credential` : `${issuer}/credential`));
|
|
2790
|
+
if (metadata?.deferred_credential_endpoint) {
|
|
2791
|
+
builder.withDeferredCredentialEndpoint(metadata.deferred_credential_endpoint);
|
|
2792
|
+
}
|
|
2793
|
+
if (credentialIdentifier) {
|
|
2794
|
+
builder.withCredentialIdentifier(credentialIdentifier);
|
|
2795
|
+
}
|
|
2796
|
+
if (credentialTypes) {
|
|
2797
|
+
builder.withCredentialType(credentialTypes);
|
|
2798
|
+
}
|
|
2799
|
+
return builder;
|
|
2800
|
+
}
|
|
2801
|
+
static async fromURI({ uri, metadata }) {
|
|
2802
|
+
const offer = await CredentialOfferClient.fromURI(uri);
|
|
2803
|
+
return _CredentialRequestClientBuilderV1_0_13.fromCredentialOfferRequest({
|
|
2804
|
+
request: offer,
|
|
2805
|
+
...offer,
|
|
2806
|
+
metadata,
|
|
2807
|
+
version: offer.version
|
|
2808
|
+
});
|
|
2809
|
+
}
|
|
2810
|
+
static fromCredentialOfferRequest(opts) {
|
|
2811
|
+
const { request, metadata } = opts;
|
|
2812
|
+
const version = opts.version ?? request.version ?? (0, import_oid4vci_common21.determineSpecVersionFromOffer)(request.original_credential_offer);
|
|
2813
|
+
if (version < import_oid4vci_common21.OpenId4VCIVersion.VER_1_0_13) {
|
|
2814
|
+
throw new Error("Versions below v1.0.13 (draft 13) are not supported.");
|
|
2815
|
+
}
|
|
2816
|
+
const builder = new _CredentialRequestClientBuilderV1_0_13();
|
|
2817
|
+
const issuer = (0, import_oid4vci_common21.getIssuerFromCredentialOfferPayload)(request.credential_offer) ?? metadata?.issuer;
|
|
2818
|
+
builder.withVersion(version);
|
|
2819
|
+
builder.withCredentialEndpoint(metadata?.credential_endpoint ?? (issuer.endsWith("/") ? `${issuer}credential` : `${issuer}/credential`));
|
|
2820
|
+
if (metadata?.deferred_credential_endpoint) {
|
|
2821
|
+
builder.withDeferredCredentialEndpoint(metadata.deferred_credential_endpoint);
|
|
2822
|
+
}
|
|
2823
|
+
const ids = request.credential_offer.credential_configuration_ids;
|
|
2824
|
+
if (ids.length && ids.length === 1) {
|
|
2825
|
+
builder.withCredentialIdentifier(ids[0]);
|
|
2826
|
+
}
|
|
2827
|
+
return builder;
|
|
2828
|
+
}
|
|
2829
|
+
static fromCredentialOffer({ credentialOffer, metadata }) {
|
|
2830
|
+
const builder = _CredentialRequestClientBuilderV1_0_13.fromCredentialOfferRequest({
|
|
2831
|
+
request: credentialOffer,
|
|
2832
|
+
metadata,
|
|
2833
|
+
version: credentialOffer.version
|
|
2834
|
+
});
|
|
2835
|
+
return builder;
|
|
2836
|
+
}
|
|
2837
|
+
withCredentialEndpointFromMetadata(metadata) {
|
|
2838
|
+
this.credentialEndpoint = metadata.credential_endpoint;
|
|
2839
|
+
return this;
|
|
2840
|
+
}
|
|
2841
|
+
withCredentialEndpoint(credentialEndpoint) {
|
|
2842
|
+
this.credentialEndpoint = credentialEndpoint;
|
|
2843
|
+
return this;
|
|
2844
|
+
}
|
|
2845
|
+
withIssuerState(issuerState) {
|
|
2846
|
+
this.issuerState = issuerState;
|
|
2847
|
+
return this;
|
|
2848
|
+
}
|
|
2849
|
+
withDeferredCredentialEndpointFromMetadata(metadata) {
|
|
2850
|
+
this.deferredCredentialEndpoint = metadata.deferred_credential_endpoint;
|
|
2851
|
+
return this;
|
|
2852
|
+
}
|
|
2853
|
+
withDeferredCredentialEndpoint(deferredCredentialEndpoint) {
|
|
2854
|
+
this.deferredCredentialEndpoint = deferredCredentialEndpoint;
|
|
2855
|
+
return this;
|
|
2856
|
+
}
|
|
2857
|
+
withDeferredCredentialAwait(deferredCredentialAwait, deferredCredentialIntervalInMS) {
|
|
2858
|
+
this.deferredCredentialAwait = deferredCredentialAwait;
|
|
2859
|
+
this.deferredCredentialIntervalInMS = deferredCredentialIntervalInMS ?? 5e3;
|
|
2860
|
+
return this;
|
|
2861
|
+
}
|
|
2862
|
+
withCredentialIdentifier(credentialIdentifier) {
|
|
2863
|
+
this.credentialIdentifier = credentialIdentifier;
|
|
2864
|
+
return this;
|
|
2865
|
+
}
|
|
2866
|
+
withCredentialType(credentialTypes) {
|
|
2867
|
+
this.credentialTypes = Array.isArray(credentialTypes) ? credentialTypes : [
|
|
2868
|
+
credentialTypes
|
|
2869
|
+
];
|
|
2870
|
+
return this;
|
|
2871
|
+
}
|
|
2872
|
+
withFormat(format) {
|
|
2873
|
+
this.format = format;
|
|
2874
|
+
return this;
|
|
2875
|
+
}
|
|
2876
|
+
withSubjectIssuance(subjectIssuance) {
|
|
2877
|
+
this.subjectIssuance = subjectIssuance;
|
|
2878
|
+
return this;
|
|
2879
|
+
}
|
|
2880
|
+
withToken(accessToken) {
|
|
2881
|
+
this.token = accessToken;
|
|
2882
|
+
return this;
|
|
2883
|
+
}
|
|
2884
|
+
withTokenFromResponse(response) {
|
|
2885
|
+
this.token = response.access_token;
|
|
2886
|
+
return this;
|
|
2887
|
+
}
|
|
2888
|
+
withVersion(version) {
|
|
2889
|
+
this.version = version;
|
|
2890
|
+
return this;
|
|
2891
|
+
}
|
|
2892
|
+
build() {
|
|
2893
|
+
if (!this.version) {
|
|
2894
|
+
this.withVersion(import_oid4vci_common21.OpenId4VCIVersion.VER_1_0_11);
|
|
2895
|
+
}
|
|
2896
|
+
return new CredentialRequestClient(this);
|
|
2897
|
+
}
|
|
2898
|
+
};
|
|
2899
|
+
|
|
2900
|
+
// lib/CredentialRequestClientBuilder.ts
|
|
2901
|
+
function isV1_0_13(builder) {
|
|
2902
|
+
return builder.withCredentialIdentifier !== void 0;
|
|
2903
|
+
}
|
|
2904
|
+
__name(isV1_0_13, "isV1_0_13");
|
|
2905
|
+
var CredentialRequestClientBuilder = class _CredentialRequestClientBuilder {
|
|
2906
|
+
static {
|
|
2907
|
+
__name(this, "CredentialRequestClientBuilder");
|
|
2908
|
+
}
|
|
2909
|
+
_builder;
|
|
2910
|
+
constructor(builder) {
|
|
2911
|
+
this._builder = builder;
|
|
2912
|
+
}
|
|
2913
|
+
static fromCredentialIssuer({ credentialIssuer, metadata, version, credentialIdentifier, credentialTypes }) {
|
|
2914
|
+
const specVersion = version ?? import_oid4vci_common22.OpenId4VCIVersion.VER_1_0_13;
|
|
2915
|
+
let builder;
|
|
2916
|
+
if (specVersion >= import_oid4vci_common22.OpenId4VCIVersion.VER_1_0_13) {
|
|
2917
|
+
builder = CredentialRequestClientBuilderV1_0_13.fromCredentialIssuer({
|
|
2918
|
+
credentialIssuer,
|
|
2919
|
+
metadata,
|
|
2920
|
+
version,
|
|
2921
|
+
credentialIdentifier,
|
|
2922
|
+
credentialTypes
|
|
2923
|
+
});
|
|
2924
|
+
} else {
|
|
2925
|
+
if (!credentialTypes || credentialTypes.length === 0) {
|
|
2926
|
+
throw new Error("CredentialTypes must be provided for v1_0_11");
|
|
2927
|
+
}
|
|
2928
|
+
builder = CredentialRequestClientBuilderV1_0_11.fromCredentialIssuer({
|
|
2929
|
+
credentialIssuer,
|
|
2930
|
+
metadata,
|
|
2931
|
+
version,
|
|
2932
|
+
credentialTypes
|
|
2933
|
+
});
|
|
2934
|
+
}
|
|
2935
|
+
return new _CredentialRequestClientBuilder(builder);
|
|
2936
|
+
}
|
|
2937
|
+
static async fromURI({ uri, metadata }) {
|
|
2938
|
+
const offer = await CredentialOfferClient.fromURI(uri);
|
|
2939
|
+
return _CredentialRequestClientBuilder.fromCredentialOfferRequest({
|
|
2940
|
+
request: offer,
|
|
2941
|
+
...offer,
|
|
2942
|
+
metadata,
|
|
2943
|
+
version: offer.version
|
|
2944
|
+
});
|
|
2945
|
+
}
|
|
2946
|
+
static fromCredentialOfferRequest(opts) {
|
|
2947
|
+
const { request } = opts;
|
|
2948
|
+
const version = opts.version ?? request.version ?? (0, import_oid4vci_common22.determineSpecVersionFromOffer)(request.original_credential_offer);
|
|
2949
|
+
let builder;
|
|
2950
|
+
if (version < import_oid4vci_common22.OpenId4VCIVersion.VER_1_0_13) {
|
|
2951
|
+
builder = CredentialRequestClientBuilderV1_0_11.fromCredentialOfferRequest(opts);
|
|
2952
|
+
} else {
|
|
2953
|
+
builder = CredentialRequestClientBuilderV1_0_13.fromCredentialOfferRequest(opts);
|
|
2954
|
+
}
|
|
2955
|
+
return new _CredentialRequestClientBuilder(builder);
|
|
2956
|
+
}
|
|
2957
|
+
static fromCredentialOffer({ credentialOffer, metadata }) {
|
|
2958
|
+
const version = (0, import_oid4vci_common22.determineSpecVersionFromOffer)(credentialOffer.credential_offer);
|
|
2959
|
+
let builder;
|
|
2960
|
+
if (version < import_oid4vci_common22.OpenId4VCIVersion.VER_1_0_13) {
|
|
2961
|
+
builder = CredentialRequestClientBuilderV1_0_11.fromCredentialOffer({
|
|
2962
|
+
credentialOffer,
|
|
2963
|
+
metadata
|
|
2964
|
+
});
|
|
2965
|
+
} else {
|
|
2966
|
+
builder = CredentialRequestClientBuilderV1_0_13.fromCredentialOffer({
|
|
2967
|
+
credentialOffer,
|
|
2968
|
+
metadata
|
|
2969
|
+
});
|
|
2970
|
+
}
|
|
2971
|
+
return new _CredentialRequestClientBuilder(builder);
|
|
2972
|
+
}
|
|
2973
|
+
getVersion() {
|
|
2974
|
+
return this._builder.version;
|
|
2975
|
+
}
|
|
2976
|
+
withCredentialEndpointFromMetadata(metadata) {
|
|
2977
|
+
if (isV1_0_13(this._builder)) {
|
|
2978
|
+
this._builder.withCredentialEndpointFromMetadata(metadata);
|
|
2979
|
+
} else {
|
|
2980
|
+
this._builder.withCredentialEndpointFromMetadata(metadata);
|
|
2981
|
+
}
|
|
2982
|
+
return this;
|
|
2983
|
+
}
|
|
2984
|
+
withCredentialEndpoint(credentialEndpoint) {
|
|
2985
|
+
this._builder.withCredentialEndpoint(credentialEndpoint);
|
|
2986
|
+
return this;
|
|
2987
|
+
}
|
|
2988
|
+
withDeferredCredentialEndpointFromMetadata(metadata) {
|
|
2989
|
+
if (isV1_0_13(this._builder)) {
|
|
2990
|
+
this._builder.withDeferredCredentialEndpointFromMetadata(metadata);
|
|
2991
|
+
} else {
|
|
2992
|
+
this._builder.withDeferredCredentialEndpointFromMetadata(metadata);
|
|
2993
|
+
}
|
|
2994
|
+
return this;
|
|
2995
|
+
}
|
|
2996
|
+
withDeferredCredentialEndpoint(deferredCredentialEndpoint) {
|
|
2997
|
+
this._builder.withDeferredCredentialEndpoint(deferredCredentialEndpoint);
|
|
2998
|
+
return this;
|
|
2999
|
+
}
|
|
3000
|
+
withDeferredCredentialAwait(deferredCredentialAwait, deferredCredentialIntervalInMS) {
|
|
3001
|
+
this._builder.withDeferredCredentialAwait(deferredCredentialAwait, deferredCredentialIntervalInMS);
|
|
3002
|
+
return this;
|
|
3003
|
+
}
|
|
3004
|
+
withCredentialIdentifier(credentialIdentifier) {
|
|
3005
|
+
if (this._builder.version === void 0 || this._builder.version < import_oid4vci_common22.OpenId4VCIVersion.VER_1_0_13) {
|
|
3006
|
+
throw new Error("Version of spec should be equal or higher than v1_0_13");
|
|
3007
|
+
}
|
|
3008
|
+
this._builder.withCredentialIdentifier(credentialIdentifier);
|
|
3009
|
+
return this;
|
|
3010
|
+
}
|
|
3011
|
+
withIssuerState(issuerState) {
|
|
3012
|
+
this._builder.withIssuerState(issuerState);
|
|
3013
|
+
return this;
|
|
3014
|
+
}
|
|
3015
|
+
withCredentialType(credentialTypes) {
|
|
3016
|
+
this._builder.withCredentialType(credentialTypes);
|
|
3017
|
+
return this;
|
|
3018
|
+
}
|
|
3019
|
+
withFormat(format) {
|
|
3020
|
+
this._builder.withFormat(format);
|
|
3021
|
+
return this;
|
|
3022
|
+
}
|
|
3023
|
+
withSubjectIssuance(subjectIssuance) {
|
|
3024
|
+
this._builder.withSubjectIssuance(subjectIssuance);
|
|
3025
|
+
return this;
|
|
3026
|
+
}
|
|
3027
|
+
withToken(accessToken) {
|
|
3028
|
+
this._builder.withToken(accessToken);
|
|
3029
|
+
return this;
|
|
3030
|
+
}
|
|
3031
|
+
withTokenFromResponse(response) {
|
|
3032
|
+
this._builder.withTokenFromResponse(response);
|
|
3033
|
+
return this;
|
|
3034
|
+
}
|
|
3035
|
+
withVersion(version) {
|
|
3036
|
+
this._builder.withVersion(version);
|
|
3037
|
+
return this;
|
|
3038
|
+
}
|
|
3039
|
+
build() {
|
|
3040
|
+
return this._builder.build();
|
|
3041
|
+
}
|
|
3042
|
+
};
|
|
3043
|
+
|
|
3044
|
+
// lib/OpenID4VCIClient.ts
|
|
3045
|
+
var import_oid4vci_common23 = require("@sphereon/oid4vci-common");
|
|
3046
|
+
var import_debug13 = __toESM(require("debug"), 1);
|
|
3047
|
+
var debug13 = (0, import_debug13.default)("sphereon:oid4vci");
|
|
3048
|
+
var OpenID4VCIClient = class _OpenID4VCIClient {
|
|
3049
|
+
static {
|
|
3050
|
+
__name(this, "OpenID4VCIClient");
|
|
3051
|
+
}
|
|
3052
|
+
_state;
|
|
3053
|
+
constructor({ credentialOffer, clientId, kid, alg, credentialIssuer, pkce, authorizationRequest, accessToken, jwk, endpointMetadata, accessTokenResponse, authorizationRequestOpts, authorizationCodeResponse, authorizationURL }) {
|
|
3054
|
+
const issuer = credentialIssuer ?? (credentialOffer ? (0, import_oid4vci_common23.getIssuerFromCredentialOfferPayload)(credentialOffer.credential_offer) : void 0);
|
|
3055
|
+
if (!issuer) {
|
|
3056
|
+
throw Error("No credential issuer supplied or deduced from offer");
|
|
3057
|
+
}
|
|
3058
|
+
this._state = {
|
|
3059
|
+
credentialOffer,
|
|
3060
|
+
credentialIssuer: issuer,
|
|
3061
|
+
kid,
|
|
3062
|
+
alg,
|
|
3063
|
+
// TODO: We need to refactor this and always explicitly call createAuthorizationRequestUrl, so we can have a credential selection first and use the kid as a default for the client id
|
|
3064
|
+
clientId: clientId ?? (credentialOffer && (0, import_oid4vci_common23.getClientIdFromCredentialOfferPayload)(credentialOffer.credential_offer)) ?? kid?.split("#")[0],
|
|
3065
|
+
pkce: {
|
|
3066
|
+
disabled: false,
|
|
3067
|
+
codeChallengeMethod: import_oid4vci_common23.CodeChallengeMethod.S256,
|
|
3068
|
+
...pkce
|
|
3069
|
+
},
|
|
3070
|
+
authorizationRequestOpts,
|
|
3071
|
+
authorizationCodeResponse,
|
|
3072
|
+
accessToken,
|
|
3073
|
+
jwk,
|
|
3074
|
+
endpointMetadata: endpointMetadata?.credentialIssuerMetadata?.authorization_server ? endpointMetadata : endpointMetadata,
|
|
3075
|
+
accessTokenResponse,
|
|
3076
|
+
authorizationURL
|
|
3077
|
+
};
|
|
3078
|
+
if (!this._state.authorizationRequestOpts) {
|
|
3079
|
+
this._state.authorizationRequestOpts = this.syncAuthorizationRequestOpts(authorizationRequest);
|
|
3080
|
+
}
|
|
3081
|
+
debug13(`Authorization req options: ${JSON.stringify(this._state.authorizationRequestOpts, null, 2)}`);
|
|
3082
|
+
}
|
|
3083
|
+
static async fromCredentialIssuer({ kid, alg, retrieveServerMetadata, clientId, credentialIssuer, pkce, authorizationRequest, createAuthorizationRequestURL, endpointMetadata }) {
|
|
3084
|
+
const client = new _OpenID4VCIClient({
|
|
3085
|
+
kid,
|
|
3086
|
+
alg,
|
|
3087
|
+
clientId: clientId ?? authorizationRequest?.clientId,
|
|
3088
|
+
credentialIssuer,
|
|
3089
|
+
pkce,
|
|
3090
|
+
authorizationRequest,
|
|
3091
|
+
endpointMetadata
|
|
3092
|
+
});
|
|
3093
|
+
if (retrieveServerMetadata === void 0 || retrieveServerMetadata) {
|
|
3094
|
+
await client.retrieveServerMetadata();
|
|
3095
|
+
}
|
|
3096
|
+
if (createAuthorizationRequestURL === void 0 || createAuthorizationRequestURL) {
|
|
3097
|
+
await client.createAuthorizationRequestUrl({
|
|
3098
|
+
authorizationRequest,
|
|
3099
|
+
pkce
|
|
3100
|
+
});
|
|
3101
|
+
}
|
|
3102
|
+
return client;
|
|
3103
|
+
}
|
|
3104
|
+
static async fromState({ state }) {
|
|
3105
|
+
const clientState = typeof state === "string" ? JSON.parse(state) : state;
|
|
3106
|
+
return new _OpenID4VCIClient(clientState);
|
|
3107
|
+
}
|
|
3108
|
+
static async fromURI({ uri, kid, alg, retrieveServerMetadata, clientId, pkce, createAuthorizationRequestURL, authorizationRequest, resolveOfferUri, endpointMetadata }) {
|
|
3109
|
+
const credentialOfferClient = await CredentialOfferClient.fromURI(uri, {
|
|
3110
|
+
resolve: resolveOfferUri
|
|
3111
|
+
});
|
|
3112
|
+
const client = new _OpenID4VCIClient({
|
|
3113
|
+
credentialOffer: credentialOfferClient,
|
|
3114
|
+
kid,
|
|
3115
|
+
alg,
|
|
3116
|
+
clientId: clientId ?? authorizationRequest?.clientId ?? credentialOfferClient.clientId,
|
|
3117
|
+
pkce,
|
|
3118
|
+
authorizationRequest,
|
|
3119
|
+
endpointMetadata
|
|
3120
|
+
});
|
|
3121
|
+
if (retrieveServerMetadata === void 0 || retrieveServerMetadata) {
|
|
3122
|
+
await client.retrieveServerMetadata();
|
|
3123
|
+
}
|
|
3124
|
+
if (credentialOfferClient.supportedFlows.includes(import_oid4vci_common23.AuthzFlowType.AUTHORIZATION_CODE_FLOW) && (createAuthorizationRequestURL === void 0 || createAuthorizationRequestURL)) {
|
|
3125
|
+
await client.createAuthorizationRequestUrl({
|
|
3126
|
+
authorizationRequest,
|
|
3127
|
+
pkce
|
|
3128
|
+
});
|
|
3129
|
+
debug13(`Authorization Request URL: ${client._state.authorizationURL}`);
|
|
3130
|
+
}
|
|
3131
|
+
return client;
|
|
3132
|
+
}
|
|
3133
|
+
/**
|
|
3134
|
+
* Allows you to create an Authorization Request URL when using an Authorization Code flow. This URL needs to be accessed using the front channel (browser)
|
|
3135
|
+
*
|
|
3136
|
+
* The Identity provider would present a login screen typically; after you authenticated, it would redirect to the provided redirectUri; which can be same device or cross-device
|
|
3137
|
+
* @param opts
|
|
3138
|
+
*/
|
|
3139
|
+
async createAuthorizationRequestUrl(opts) {
|
|
3140
|
+
if (!this._state.authorizationURL) {
|
|
3141
|
+
this.calculatePKCEOpts(opts?.pkce);
|
|
3142
|
+
this._state.authorizationRequestOpts = this.syncAuthorizationRequestOpts(opts?.authorizationRequest);
|
|
3143
|
+
if (!this._state.authorizationRequestOpts) {
|
|
3144
|
+
throw Error(`No Authorization Request options present or provided in this call`);
|
|
3145
|
+
}
|
|
3146
|
+
if (this._state.endpointMetadata?.credentialIssuerMetadata && "authorization_endpoint" in this._state.endpointMetadata.credentialIssuerMetadata) {
|
|
3147
|
+
this._state.endpointMetadata.authorization_endpoint = this._state.endpointMetadata.credentialIssuerMetadata.authorization_endpoint;
|
|
3148
|
+
}
|
|
3149
|
+
if (this.version() <= import_oid4vci_common23.OpenId4VCIVersion.VER_1_0_11) {
|
|
3150
|
+
this._state.authorizationURL = await createAuthorizationRequestUrlV1_0_11({
|
|
3151
|
+
pkce: this._state.pkce,
|
|
3152
|
+
endpointMetadata: this.endpointMetadata,
|
|
3153
|
+
authorizationRequest: this._state.authorizationRequestOpts,
|
|
3154
|
+
credentialOffer: this.credentialOffer,
|
|
3155
|
+
credentialsSupported: Object.values(this.getCredentialsSupported(true))
|
|
3156
|
+
});
|
|
3157
|
+
} else {
|
|
3158
|
+
this._state.authorizationURL = await createAuthorizationRequestUrl({
|
|
3159
|
+
pkce: this._state.pkce,
|
|
3160
|
+
endpointMetadata: this.endpointMetadata,
|
|
3161
|
+
authorizationRequest: this._state.authorizationRequestOpts,
|
|
3162
|
+
credentialOffer: this.credentialOffer,
|
|
3163
|
+
credentialConfigurationSupported: this.getCredentialsSupported(false)
|
|
3164
|
+
});
|
|
3165
|
+
}
|
|
3166
|
+
}
|
|
3167
|
+
return this._state.authorizationURL;
|
|
3168
|
+
}
|
|
3169
|
+
async retrieveServerMetadata() {
|
|
3170
|
+
this.assertIssuerData();
|
|
3171
|
+
if (!this._state.endpointMetadata) {
|
|
3172
|
+
if (this.credentialOffer) {
|
|
3173
|
+
this._state.endpointMetadata = await MetadataClient.retrieveAllMetadataFromCredentialOffer(this.credentialOffer);
|
|
3174
|
+
} else if (this._state.credentialIssuer) {
|
|
3175
|
+
this._state.endpointMetadata = await MetadataClient.retrieveAllMetadata(this._state.credentialIssuer);
|
|
3176
|
+
} else {
|
|
3177
|
+
throw Error(`Cannot retrieve issuer metadata without either a credential offer, or issuer value`);
|
|
3178
|
+
}
|
|
3179
|
+
}
|
|
3180
|
+
return this.endpointMetadata;
|
|
3181
|
+
}
|
|
3182
|
+
calculatePKCEOpts(pkce) {
|
|
3183
|
+
this._state.pkce = generateMissingPKCEOpts({
|
|
3184
|
+
...this._state.pkce,
|
|
3185
|
+
...pkce
|
|
3186
|
+
});
|
|
3187
|
+
}
|
|
3188
|
+
async acquireAuthorizationChallengeCode(opts) {
|
|
3189
|
+
const response = await acquireAuthorizationChallengeAuthCode({
|
|
3190
|
+
metadata: this.endpointMetadata,
|
|
3191
|
+
credentialIssuer: this.getIssuer(),
|
|
3192
|
+
clientId: this._state.clientId ?? this._state.authorizationRequestOpts?.clientId,
|
|
3193
|
+
...opts
|
|
3194
|
+
});
|
|
3195
|
+
if (response.errorBody) {
|
|
3196
|
+
debug13(`Authorization code error:\r
|
|
3197
|
+
${JSON.stringify(response.errorBody)}`);
|
|
3198
|
+
const error = response.errorBody;
|
|
3199
|
+
return Promise.reject(error);
|
|
3200
|
+
} else if (!response.successBody) {
|
|
3201
|
+
debug13(`Authorization code error. No success body`);
|
|
3202
|
+
return Promise.reject(Error(`Retrieving an authorization code token from ${this._state.endpointMetadata?.authorization_challenge_endpoint} for issuer ${this.getIssuer()} failed as there was no success response body`));
|
|
3203
|
+
}
|
|
3204
|
+
return {
|
|
3205
|
+
...response.successBody
|
|
3206
|
+
};
|
|
3207
|
+
}
|
|
3208
|
+
async acquireAccessToken(opts) {
|
|
3209
|
+
const { pin, clientId = this._state.clientId ?? this._state.authorizationRequestOpts?.clientId } = opts ?? {};
|
|
3210
|
+
let { redirectUri } = opts ?? {};
|
|
3211
|
+
const code = this.getAuthorizationCode(opts?.authorizationResponse, opts?.code);
|
|
3212
|
+
if (opts?.codeVerifier) {
|
|
3213
|
+
this._state.pkce.codeVerifier = opts.codeVerifier;
|
|
3214
|
+
}
|
|
3215
|
+
this.assertIssuerData();
|
|
3216
|
+
const asOpts = {
|
|
3217
|
+
...opts?.asOpts
|
|
3218
|
+
};
|
|
3219
|
+
const kid = asOpts.clientOpts?.kid ?? this._state.kid ?? this._state.authorizationRequestOpts?.requestObjectOpts?.kid;
|
|
3220
|
+
const clientAssertionType = asOpts.clientOpts?.clientAssertionType ?? (kid && clientId && typeof asOpts.clientOpts?.signCallbacks?.signCallback === "function" ? "urn:ietf:params:oauth:client-assertion-type:jwt-bearer" : void 0);
|
|
3221
|
+
if (this.isEBSI() || clientId && kid) {
|
|
3222
|
+
if (!clientId) {
|
|
3223
|
+
throw Error(`Client id expected for EBSI`);
|
|
3224
|
+
}
|
|
3225
|
+
asOpts.clientOpts = {
|
|
3226
|
+
...asOpts.clientOpts,
|
|
3227
|
+
clientId,
|
|
3228
|
+
...kid && {
|
|
3229
|
+
kid
|
|
3230
|
+
},
|
|
3231
|
+
...clientAssertionType && {
|
|
3232
|
+
clientAssertionType
|
|
3233
|
+
},
|
|
3234
|
+
signCallbacks: asOpts.clientOpts?.signCallbacks ?? this._state.authorizationRequestOpts?.requestObjectOpts?.signCallbacks
|
|
3235
|
+
};
|
|
3236
|
+
}
|
|
3237
|
+
if (clientId) {
|
|
3238
|
+
this._state.clientId = clientId;
|
|
3239
|
+
if (!asOpts.clientOpts) {
|
|
3240
|
+
asOpts.clientOpts = {
|
|
3241
|
+
clientId
|
|
3242
|
+
};
|
|
3243
|
+
}
|
|
3244
|
+
asOpts.clientOpts.clientId = clientId;
|
|
3245
|
+
}
|
|
3246
|
+
if (!this._state.accessTokenResponse) {
|
|
3247
|
+
const accessTokenClient = this.version() <= import_oid4vci_common23.OpenId4VCIVersion.VER_1_0_12 ? new AccessTokenClientV1_0_11() : new AccessTokenClient();
|
|
3248
|
+
if (redirectUri && redirectUri !== this._state.authorizationRequestOpts?.redirectUri) {
|
|
3249
|
+
console.log(`Redirect URI mismatch between access-token (${redirectUri}) and authorization request (${this._state.authorizationRequestOpts?.redirectUri}). According to the specification that is not allowed.`);
|
|
3250
|
+
}
|
|
3251
|
+
if (this._state.authorizationRequestOpts?.redirectUri && !redirectUri) {
|
|
3252
|
+
redirectUri = this._state.authorizationRequestOpts.redirectUri;
|
|
3253
|
+
}
|
|
3254
|
+
const response = await accessTokenClient.acquireAccessToken({
|
|
3255
|
+
credentialOffer: this.credentialOffer,
|
|
3256
|
+
metadata: this.endpointMetadata,
|
|
3257
|
+
credentialIssuer: this.getIssuer(),
|
|
3258
|
+
pin,
|
|
3259
|
+
...!this._state.pkce.disabled && {
|
|
3260
|
+
codeVerifier: this._state.pkce.codeVerifier
|
|
3261
|
+
},
|
|
3262
|
+
code,
|
|
3263
|
+
redirectUri,
|
|
3264
|
+
asOpts,
|
|
3265
|
+
...opts?.createDPoPOpts && {
|
|
3266
|
+
createDPoPOpts: opts.createDPoPOpts
|
|
3267
|
+
},
|
|
3268
|
+
...opts?.additionalRequestParams && {
|
|
3269
|
+
additionalParams: opts.additionalRequestParams
|
|
3270
|
+
}
|
|
3271
|
+
});
|
|
3272
|
+
if (response.errorBody) {
|
|
3273
|
+
debug13(`Access token error:\r
|
|
3274
|
+
${JSON.stringify(response.errorBody)}`);
|
|
3275
|
+
throw Error(`Retrieving an access token from ${this._state.endpointMetadata?.token_endpoint} for issuer ${this.getIssuer()} failed with status: ${response.origResponse.status}`);
|
|
3276
|
+
} else if (!response.successBody) {
|
|
3277
|
+
debug13(`Access token error. No success body`);
|
|
3278
|
+
throw Error(`Retrieving an access token from ${this._state.endpointMetadata?.token_endpoint} for issuer ${this.getIssuer()} failed as there was no success response body`);
|
|
3279
|
+
}
|
|
3280
|
+
this._state.accessTokenResponse = response.successBody;
|
|
3281
|
+
this._state.dpopResponseParams = response.params;
|
|
3282
|
+
this._state.accessToken = response.successBody.access_token;
|
|
3283
|
+
}
|
|
3284
|
+
return {
|
|
3285
|
+
...this.accessTokenResponse,
|
|
3286
|
+
...this.dpopResponseParams && {
|
|
3287
|
+
params: this.dpopResponseParams
|
|
3288
|
+
}
|
|
3289
|
+
};
|
|
3290
|
+
}
|
|
3291
|
+
async acquireCredentials({ credentialTypes, context, proofCallbacks, format, kid, jwk, alg, jti, deferredCredentialAwait, deferredCredentialIntervalInMS, createDPoPOpts }) {
|
|
3292
|
+
if ([
|
|
3293
|
+
jwk,
|
|
3294
|
+
kid
|
|
3295
|
+
].filter((v) => v !== void 0).length > 1) {
|
|
3296
|
+
throw new Error(import_oid4vci_common23.KID_JWK_X5C_ERROR + `. jwk: ${jwk !== void 0}, kid: ${kid !== void 0}`);
|
|
3297
|
+
}
|
|
3298
|
+
if (alg) this._state.alg = alg;
|
|
3299
|
+
if (jwk) this._state.jwk = jwk;
|
|
3300
|
+
if (kid) this._state.kid = kid;
|
|
3301
|
+
let requestBuilder;
|
|
3302
|
+
if (this.version() < import_oid4vci_common23.OpenId4VCIVersion.VER_1_0_13) {
|
|
3303
|
+
requestBuilder = this.credentialOffer ? CredentialRequestClientBuilderV1_0_11.fromCredentialOffer({
|
|
3304
|
+
credentialOffer: this.credentialOffer,
|
|
3305
|
+
metadata: this.endpointMetadata
|
|
3306
|
+
}) : CredentialRequestClientBuilderV1_0_11.fromCredentialIssuer({
|
|
3307
|
+
credentialIssuer: this.getIssuer(),
|
|
3308
|
+
credentialTypes,
|
|
3309
|
+
metadata: this.endpointMetadata,
|
|
3310
|
+
version: this.version()
|
|
3311
|
+
});
|
|
3312
|
+
} else {
|
|
3313
|
+
requestBuilder = this.credentialOffer ? CredentialRequestClientBuilderV1_0_13.fromCredentialOffer({
|
|
3314
|
+
credentialOffer: this.credentialOffer,
|
|
3315
|
+
metadata: this.endpointMetadata
|
|
3316
|
+
}) : CredentialRequestClientBuilderV1_0_13.fromCredentialIssuer({
|
|
3317
|
+
credentialIssuer: this.getIssuer(),
|
|
3318
|
+
credentialTypes,
|
|
3319
|
+
metadata: this.endpointMetadata,
|
|
3320
|
+
version: this.version()
|
|
3321
|
+
});
|
|
3322
|
+
}
|
|
3323
|
+
const issuerState = this.issuerSupportedFlowTypes().includes(import_oid4vci_common23.AuthzFlowType.AUTHORIZATION_CODE_FLOW) && this._state.authorizationCodeResponse && !this.accessTokenResponse?.c_nonce && this._state.credentialOffer?.issuerState ? this._state.credentialOffer.issuerState : void 0;
|
|
3324
|
+
requestBuilder.withIssuerState(issuerState);
|
|
3325
|
+
requestBuilder.withTokenFromResponse(this.accessTokenResponse);
|
|
3326
|
+
requestBuilder.withDeferredCredentialAwait(deferredCredentialAwait ?? false, deferredCredentialIntervalInMS);
|
|
3327
|
+
let subjectIssuance;
|
|
3328
|
+
if (this.endpointMetadata?.credentialIssuerMetadata) {
|
|
3329
|
+
const metadata = this.endpointMetadata.credentialIssuerMetadata;
|
|
3330
|
+
const types = Array.isArray(credentialTypes) ? credentialTypes : [
|
|
3331
|
+
credentialTypes
|
|
3332
|
+
];
|
|
3333
|
+
if (metadata.credentials_supported && Array.isArray(metadata.credentials_supported)) {
|
|
3334
|
+
let typeSupported = false;
|
|
3335
|
+
metadata.credentials_supported.forEach((supportedCredential) => {
|
|
3336
|
+
const subTypes = (0, import_oid4vci_common23.getTypesFromCredentialSupported)(supportedCredential);
|
|
3337
|
+
if (subTypes.every((t, i) => types[i] === t) || types.length === 1 && (types[0] === supportedCredential.id || subTypes.includes(types[0]))) {
|
|
3338
|
+
typeSupported = true;
|
|
3339
|
+
if (supportedCredential.credential_subject_issuance) {
|
|
3340
|
+
subjectIssuance = {
|
|
3341
|
+
credential_subject_issuance: supportedCredential.credential_subject_issuance
|
|
3342
|
+
};
|
|
3343
|
+
}
|
|
3344
|
+
}
|
|
3345
|
+
});
|
|
3346
|
+
if (!typeSupported) {
|
|
3347
|
+
console.log(`Not all credential types ${JSON.stringify(credentialTypes)} are present in metadata for ${this.getIssuer()}`);
|
|
3348
|
+
}
|
|
3349
|
+
} else if (metadata.credentials_supported && !Array.isArray(metadata.credentials_supported)) {
|
|
3350
|
+
const credentialsSupported = metadata.credentials_supported;
|
|
3351
|
+
if (types.some((type) => !metadata.credentials_supported || !credentialsSupported[type])) {
|
|
3352
|
+
throw Error(`Not all credential types ${JSON.stringify(credentialTypes)} are supported by issuer ${this.getIssuer()}`);
|
|
3353
|
+
}
|
|
3354
|
+
}
|
|
3355
|
+
}
|
|
3356
|
+
if (subjectIssuance) {
|
|
3357
|
+
requestBuilder.withSubjectIssuance(subjectIssuance);
|
|
3358
|
+
}
|
|
3359
|
+
const credentialRequestClient = requestBuilder.build();
|
|
3360
|
+
const proofBuilder = ProofOfPossessionBuilder.fromAccessTokenResponse({
|
|
3361
|
+
accessTokenResponse: this.accessTokenResponse,
|
|
3362
|
+
callbacks: proofCallbacks,
|
|
3363
|
+
version: this.version()
|
|
3364
|
+
}).withIssuer(this.getIssuer()).withAlg(this.alg);
|
|
3365
|
+
if (this._state.jwk) {
|
|
3366
|
+
proofBuilder.withJWK(this._state.jwk);
|
|
3367
|
+
}
|
|
3368
|
+
if (this._state.kid) {
|
|
3369
|
+
proofBuilder.withKid(this._state.kid);
|
|
3370
|
+
}
|
|
3371
|
+
if (this.clientId) {
|
|
3372
|
+
proofBuilder.withClientId(this.clientId);
|
|
3373
|
+
}
|
|
3374
|
+
if (jti) {
|
|
3375
|
+
proofBuilder.withJti(jti);
|
|
3376
|
+
}
|
|
3377
|
+
const response = await credentialRequestClient.acquireCredentialsUsingProof({
|
|
3378
|
+
proofInput: proofBuilder,
|
|
3379
|
+
credentialTypes,
|
|
3380
|
+
context,
|
|
3381
|
+
format,
|
|
3382
|
+
subjectIssuance,
|
|
3383
|
+
createDPoPOpts
|
|
3384
|
+
});
|
|
3385
|
+
this._state.dpopResponseParams = response.params;
|
|
3386
|
+
if (response.errorBody) {
|
|
3387
|
+
debug13(`Credential request error:\r
|
|
3388
|
+
${JSON.stringify(response.errorBody)}`);
|
|
3389
|
+
throw Error(`Retrieving a credential from ${this._state.endpointMetadata?.credential_endpoint} for issuer ${this.getIssuer()} failed with status: ${response.origResponse.status}`);
|
|
3390
|
+
} else if (!response.successBody) {
|
|
3391
|
+
debug13(`Credential request error. No success body`);
|
|
3392
|
+
throw Error(`Retrieving a credential from ${this._state.endpointMetadata?.credential_endpoint} for issuer ${this.getIssuer()} failed as there was no success response body`);
|
|
3393
|
+
}
|
|
3394
|
+
return {
|
|
3395
|
+
...response.successBody,
|
|
3396
|
+
...this.dpopResponseParams && {
|
|
3397
|
+
params: this.dpopResponseParams
|
|
3398
|
+
},
|
|
3399
|
+
access_token: response.access_token
|
|
3400
|
+
};
|
|
3401
|
+
}
|
|
3402
|
+
async exportState() {
|
|
3403
|
+
return JSON.stringify(this._state);
|
|
3404
|
+
}
|
|
3405
|
+
getCredentialsSupported(restrictToInitiationTypes, format) {
|
|
3406
|
+
return (0, import_oid4vci_common23.getSupportedCredentials)({
|
|
3407
|
+
issuerMetadata: this.endpointMetadata.credentialIssuerMetadata,
|
|
3408
|
+
version: this.version(),
|
|
3409
|
+
format,
|
|
3410
|
+
types: restrictToInitiationTypes ? this.getCredentialOfferTypes() : void 0
|
|
3411
|
+
});
|
|
3412
|
+
}
|
|
3413
|
+
async sendNotification(credentialRequestOpts, request, accessToken) {
|
|
3414
|
+
return sendNotification(credentialRequestOpts, request, accessToken ?? this._state.accessToken ?? this._state.accessTokenResponse?.access_token);
|
|
3415
|
+
}
|
|
3416
|
+
getCredentialOfferTypes() {
|
|
3417
|
+
if (!this.credentialOffer) {
|
|
3418
|
+
return [];
|
|
3419
|
+
} else if (this.version() < import_oid4vci_common23.OpenId4VCIVersion.VER_1_0_11) {
|
|
3420
|
+
const orig = this.credentialOffer.original_credential_offer;
|
|
3421
|
+
const types = typeof orig.credential_type === "string" ? [
|
|
3422
|
+
orig.credential_type
|
|
3423
|
+
] : orig.credential_type;
|
|
3424
|
+
const result = [];
|
|
3425
|
+
result[0] = types;
|
|
3426
|
+
return result;
|
|
3427
|
+
} else if (this.version() < import_oid4vci_common23.OpenId4VCIVersion.VER_1_0_13) {
|
|
3428
|
+
return this.credentialOffer.credential_offer.credentials.map((c) => (0, import_oid4vci_common23.getTypesFromObject)(c) ?? []);
|
|
3429
|
+
}
|
|
3430
|
+
return void 0;
|
|
3431
|
+
}
|
|
3432
|
+
issuerSupportedFlowTypes() {
|
|
3433
|
+
return this.credentialOffer?.supportedFlows ?? (this._state.endpointMetadata?.credentialIssuerMetadata?.authorization_endpoint ?? this._state.endpointMetadata?.authorization_server ? [
|
|
3434
|
+
import_oid4vci_common23.AuthzFlowType.AUTHORIZATION_CODE_FLOW
|
|
3435
|
+
] : []);
|
|
3436
|
+
}
|
|
3437
|
+
isFlowTypeSupported(flowType) {
|
|
3438
|
+
return this.issuerSupportedFlowTypes().includes(flowType);
|
|
3439
|
+
}
|
|
3440
|
+
get authorizationURL() {
|
|
3441
|
+
return this._state.authorizationURL;
|
|
3442
|
+
}
|
|
3443
|
+
hasAuthorizationURL() {
|
|
3444
|
+
return !!this.authorizationURL;
|
|
3445
|
+
}
|
|
3446
|
+
get credentialOffer() {
|
|
3447
|
+
return this._state.credentialOffer;
|
|
3448
|
+
}
|
|
3449
|
+
version() {
|
|
3450
|
+
if (this.credentialOffer?.version && this.credentialOffer.version !== import_oid4vci_common23.OpenId4VCIVersion.VER_UNKNOWN) {
|
|
3451
|
+
return this.credentialOffer.version;
|
|
3452
|
+
}
|
|
3453
|
+
const metadata = this._state.endpointMetadata;
|
|
3454
|
+
if (metadata?.credentialIssuerMetadata) {
|
|
3455
|
+
const versions = (0, import_oid4vci_common23.determineVersionsFromIssuerMetadata)(metadata.credentialIssuerMetadata);
|
|
3456
|
+
if (versions.length > 0 && !versions.includes(import_oid4vci_common23.OpenId4VCIVersion.VER_UNKNOWN)) {
|
|
3457
|
+
return versions[0];
|
|
3458
|
+
}
|
|
3459
|
+
}
|
|
3460
|
+
return import_oid4vci_common23.OpenId4VCIVersion.VER_1_0_13;
|
|
3461
|
+
}
|
|
3462
|
+
get endpointMetadata() {
|
|
3463
|
+
this.assertServerMetadata();
|
|
3464
|
+
return this._state.endpointMetadata;
|
|
3465
|
+
}
|
|
3466
|
+
get kid() {
|
|
3467
|
+
this.assertIssuerData();
|
|
3468
|
+
if (!this._state.kid) {
|
|
3469
|
+
throw new Error("No value for kid is supplied");
|
|
3470
|
+
}
|
|
3471
|
+
return this._state.kid;
|
|
3472
|
+
}
|
|
3473
|
+
get alg() {
|
|
3474
|
+
this.assertIssuerData();
|
|
3475
|
+
if (!this._state.alg) {
|
|
3476
|
+
throw new Error("No value for alg is supplied");
|
|
3477
|
+
}
|
|
3478
|
+
return this._state.alg;
|
|
3479
|
+
}
|
|
3480
|
+
set clientId(value) {
|
|
3481
|
+
this._state.clientId = value;
|
|
3482
|
+
}
|
|
3483
|
+
get clientId() {
|
|
3484
|
+
return this._state.clientId;
|
|
3485
|
+
}
|
|
3486
|
+
hasAccessTokenResponse() {
|
|
3487
|
+
return !!this._state.accessTokenResponse;
|
|
3488
|
+
}
|
|
3489
|
+
get accessTokenResponse() {
|
|
3490
|
+
this.assertAccessToken();
|
|
3491
|
+
return this._state.accessTokenResponse;
|
|
3492
|
+
}
|
|
3493
|
+
get dpopResponseParams() {
|
|
3494
|
+
return this._state.dpopResponseParams;
|
|
3495
|
+
}
|
|
3496
|
+
getIssuer() {
|
|
3497
|
+
this.assertIssuerData();
|
|
3498
|
+
return this._state.credentialIssuer;
|
|
3499
|
+
}
|
|
3500
|
+
getAccessTokenEndpoint() {
|
|
3501
|
+
this.assertIssuerData();
|
|
3502
|
+
if (this.endpointMetadata) {
|
|
3503
|
+
return this.endpointMetadata.token_endpoint;
|
|
3504
|
+
}
|
|
3505
|
+
return this.version() <= import_oid4vci_common23.OpenId4VCIVersion.VER_1_0_12 ? AccessTokenClientV1_0_11.determineTokenURL({
|
|
3506
|
+
issuerOpts: {
|
|
3507
|
+
issuer: this.getIssuer()
|
|
3508
|
+
}
|
|
3509
|
+
}) : AccessTokenClient.determineTokenURL({
|
|
3510
|
+
issuerOpts: {
|
|
3511
|
+
issuer: this.getIssuer()
|
|
3512
|
+
}
|
|
3513
|
+
});
|
|
3514
|
+
}
|
|
3515
|
+
getCredentialEndpoint() {
|
|
3516
|
+
this.assertIssuerData();
|
|
3517
|
+
return this.endpointMetadata ? this.endpointMetadata.credential_endpoint : `${this.getIssuer()}/credential`;
|
|
3518
|
+
}
|
|
3519
|
+
getAuthorizationChallengeEndpoint() {
|
|
3520
|
+
this.assertIssuerData();
|
|
3521
|
+
return this.endpointMetadata?.authorization_challenge_endpoint;
|
|
3522
|
+
}
|
|
3523
|
+
hasAuthorizationChallengeEndpoint() {
|
|
3524
|
+
return !!this.getAuthorizationChallengeEndpoint();
|
|
3525
|
+
}
|
|
3526
|
+
hasDeferredCredentialEndpoint() {
|
|
3527
|
+
return !!this.getAccessTokenEndpoint();
|
|
3528
|
+
}
|
|
3529
|
+
getDeferredCredentialEndpoint() {
|
|
3530
|
+
this.assertIssuerData();
|
|
3531
|
+
return this.endpointMetadata ? this.endpointMetadata.credential_endpoint : `${this.getIssuer()}/credential`;
|
|
3532
|
+
}
|
|
3533
|
+
/**
|
|
3534
|
+
* Too bad we need a method like this, but EBSI is not exposing metadata
|
|
3535
|
+
*/
|
|
3536
|
+
isEBSI() {
|
|
3537
|
+
if (this.credentialOffer && this.credentialOffer?.credential_offer?.credentials?.find((cred) => (
|
|
3538
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
3539
|
+
// @ts-ignore
|
|
3540
|
+
typeof cred !== "string" && "trust_framework" in cred && "name" in cred.trust_framework && cred.trust_framework.name.includes("ebsi")
|
|
3541
|
+
))) {
|
|
3542
|
+
return true;
|
|
3543
|
+
}
|
|
3544
|
+
return this.clientId?.includes("ebsi") || this._state.kid?.includes("did:ebsi:") || this.getIssuer().includes("ebsi") || this.endpointMetadata.credentialIssuerMetadata?.authorization_endpoint?.includes("ebsi.eu") || this.endpointMetadata.credentialIssuerMetadata?.authorization_server?.includes("ebsi.eu");
|
|
3545
|
+
}
|
|
3546
|
+
assertIssuerData() {
|
|
3547
|
+
if (!this._state.credentialIssuer) {
|
|
3548
|
+
throw Error(`No credential issuer value present`);
|
|
3549
|
+
} else if (!this._state.credentialOffer && this._state.endpointMetadata && this.issuerSupportedFlowTypes().length === 0) {
|
|
3550
|
+
throw Error(`No issuance initiation or credential offer present`);
|
|
3551
|
+
}
|
|
3552
|
+
}
|
|
3553
|
+
assertServerMetadata() {
|
|
3554
|
+
if (!this._state.endpointMetadata) {
|
|
3555
|
+
throw Error("No server metadata");
|
|
3556
|
+
}
|
|
3557
|
+
}
|
|
3558
|
+
assertAccessToken() {
|
|
3559
|
+
if (!this._state.accessTokenResponse) {
|
|
3560
|
+
throw Error(`No access token present`);
|
|
3561
|
+
}
|
|
3562
|
+
}
|
|
3563
|
+
syncAuthorizationRequestOpts(opts) {
|
|
3564
|
+
const requestObjectOpts = {
|
|
3565
|
+
...this._state?.authorizationRequestOpts?.requestObjectOpts,
|
|
3566
|
+
...opts?.requestObjectOpts
|
|
3567
|
+
};
|
|
3568
|
+
let authorizationRequestOpts = {
|
|
3569
|
+
...this._state?.authorizationRequestOpts,
|
|
3570
|
+
...opts,
|
|
3571
|
+
...requestObjectOpts && {
|
|
3572
|
+
requestObjectOpts
|
|
3573
|
+
}
|
|
3574
|
+
};
|
|
3575
|
+
if (!authorizationRequestOpts) {
|
|
3576
|
+
authorizationRequestOpts = {
|
|
3577
|
+
redirectUri: `${import_oid4vci_common23.DefaultURISchemes.CREDENTIAL_OFFER}://`
|
|
3578
|
+
};
|
|
3579
|
+
}
|
|
3580
|
+
const clientId = authorizationRequestOpts.clientId ?? this._state.clientId;
|
|
3581
|
+
this._state.clientId = clientId;
|
|
3582
|
+
authorizationRequestOpts.clientId = clientId;
|
|
3583
|
+
return authorizationRequestOpts;
|
|
3584
|
+
}
|
|
3585
|
+
getAuthorizationCode = /* @__PURE__ */ __name((authorizationResponse, code) => {
|
|
3586
|
+
if (authorizationResponse) {
|
|
3587
|
+
this._state.authorizationCodeResponse = {
|
|
3588
|
+
...(0, import_oid4vci_common23.toAuthorizationResponsePayload)(authorizationResponse)
|
|
3589
|
+
};
|
|
3590
|
+
} else if (code) {
|
|
3591
|
+
this._state.authorizationCodeResponse = {
|
|
3592
|
+
code
|
|
3593
|
+
};
|
|
3594
|
+
}
|
|
3595
|
+
return this._state.authorizationCodeResponse?.code ?? this._state.authorizationCodeResponse?.authorization_code;
|
|
3596
|
+
}, "getAuthorizationCode");
|
|
3597
|
+
};
|
|
3598
|
+
|
|
3599
|
+
// lib/OpenID4VCIClientV1_0_13.ts
|
|
3600
|
+
var import_oid4vci_common24 = require("@sphereon/oid4vci-common");
|
|
3601
|
+
var import_debug14 = __toESM(require("debug"), 1);
|
|
3602
|
+
var debug14 = (0, import_debug14.default)("sphereon:oid4vci");
|
|
3603
|
+
var OpenID4VCIClientV1_0_13 = class _OpenID4VCIClientV1_0_13 {
|
|
3604
|
+
static {
|
|
3605
|
+
__name(this, "OpenID4VCIClientV1_0_13");
|
|
3606
|
+
}
|
|
3607
|
+
_state;
|
|
3608
|
+
constructor({ credentialOffer, clientId, kid, alg, credentialIssuer, pkce, authorizationRequest, accessToken, jwk, endpointMetadata, accessTokenResponse, authorizationRequestOpts, authorizationCodeResponse, authorizationURL }) {
|
|
3609
|
+
const issuer = credentialIssuer ?? (credentialOffer ? (0, import_oid4vci_common24.getIssuerFromCredentialOfferPayload)(credentialOffer.credential_offer) : void 0);
|
|
3610
|
+
if (!issuer) {
|
|
3611
|
+
throw Error("No credential issuer supplied or deduced from offer");
|
|
3612
|
+
}
|
|
3613
|
+
this._state = {
|
|
3614
|
+
credentialOffer,
|
|
3615
|
+
credentialIssuer: issuer,
|
|
3616
|
+
kid,
|
|
3617
|
+
alg,
|
|
3618
|
+
// TODO: We need to refactor this and always explicitly call createAuthorizationRequestUrl, so we can have a credential selection first and use the kid as a default for the client id
|
|
3619
|
+
clientId: clientId ?? (credentialOffer && (0, import_oid4vci_common24.getClientIdFromCredentialOfferPayload)(credentialOffer.credential_offer)) ?? kid?.split("#")[0],
|
|
3620
|
+
pkce: {
|
|
3621
|
+
disabled: false,
|
|
3622
|
+
codeChallengeMethod: import_oid4vci_common24.CodeChallengeMethod.S256,
|
|
3623
|
+
...pkce
|
|
3624
|
+
},
|
|
3625
|
+
authorizationRequestOpts,
|
|
3626
|
+
authorizationCodeResponse,
|
|
3627
|
+
accessToken,
|
|
3628
|
+
jwk,
|
|
3629
|
+
endpointMetadata,
|
|
3630
|
+
accessTokenResponse,
|
|
3631
|
+
authorizationURL
|
|
3632
|
+
};
|
|
3633
|
+
if (!this._state.authorizationRequestOpts) {
|
|
3634
|
+
this._state.authorizationRequestOpts = this.syncAuthorizationRequestOpts(authorizationRequest);
|
|
3635
|
+
}
|
|
3636
|
+
debug14(`Authorization req options: ${JSON.stringify(this._state.authorizationRequestOpts, null, 2)}`);
|
|
3637
|
+
}
|
|
3638
|
+
static async fromCredentialIssuer({ kid, alg, retrieveServerMetadata, clientId, credentialIssuer, pkce, authorizationRequest, createAuthorizationRequestURL }) {
|
|
3639
|
+
const client = new _OpenID4VCIClientV1_0_13({
|
|
3640
|
+
kid,
|
|
3641
|
+
alg,
|
|
3642
|
+
clientId: clientId ?? authorizationRequest?.clientId,
|
|
3643
|
+
credentialIssuer,
|
|
3644
|
+
pkce,
|
|
3645
|
+
authorizationRequest
|
|
3646
|
+
});
|
|
3647
|
+
if (retrieveServerMetadata === void 0 || retrieveServerMetadata) {
|
|
3648
|
+
await client.retrieveServerMetadata();
|
|
3649
|
+
}
|
|
3650
|
+
if (createAuthorizationRequestURL === void 0 || createAuthorizationRequestURL) {
|
|
3651
|
+
await client.createAuthorizationRequestUrl({
|
|
3652
|
+
authorizationRequest,
|
|
3653
|
+
pkce
|
|
3654
|
+
});
|
|
3655
|
+
}
|
|
3656
|
+
return client;
|
|
3657
|
+
}
|
|
3658
|
+
static async fromState({ state }) {
|
|
3659
|
+
const clientState = typeof state === "string" ? JSON.parse(state) : state;
|
|
3660
|
+
return new _OpenID4VCIClientV1_0_13(clientState);
|
|
3661
|
+
}
|
|
3662
|
+
static async fromURI({ uri, kid, alg, retrieveServerMetadata, clientId, pkce, createAuthorizationRequestURL, authorizationRequest, resolveOfferUri }) {
|
|
3663
|
+
const credentialOfferClient = await CredentialOfferClient.fromURI(uri, {
|
|
3664
|
+
resolve: resolveOfferUri
|
|
3665
|
+
});
|
|
3666
|
+
const client = new _OpenID4VCIClientV1_0_13({
|
|
3667
|
+
credentialOffer: credentialOfferClient,
|
|
3668
|
+
kid,
|
|
3669
|
+
alg,
|
|
3670
|
+
clientId: clientId ?? authorizationRequest?.clientId ?? credentialOfferClient.clientId,
|
|
3671
|
+
pkce,
|
|
3672
|
+
authorizationRequest
|
|
3673
|
+
});
|
|
3674
|
+
if (retrieveServerMetadata === void 0 || retrieveServerMetadata) {
|
|
3675
|
+
await client.retrieveServerMetadata();
|
|
3676
|
+
}
|
|
3677
|
+
if (credentialOfferClient.supportedFlows.includes(import_oid4vci_common24.AuthzFlowType.AUTHORIZATION_CODE_FLOW) && (createAuthorizationRequestURL === void 0 || createAuthorizationRequestURL)) {
|
|
3678
|
+
await client.createAuthorizationRequestUrl({
|
|
3679
|
+
authorizationRequest,
|
|
3680
|
+
pkce
|
|
3681
|
+
});
|
|
3682
|
+
debug14(`Authorization Request URL: ${client._state.authorizationURL}`);
|
|
3683
|
+
}
|
|
3684
|
+
return client;
|
|
3685
|
+
}
|
|
3686
|
+
/**
|
|
3687
|
+
* Allows you to create an Authorization Request URL when using an Authorization Code flow. This URL needs to be accessed using the front channel (browser)
|
|
3688
|
+
*
|
|
3689
|
+
* The Identity provider would present a login screen typically; after you authenticated, it would redirect to the provided redirectUri; which can be same device or cross-device
|
|
3690
|
+
* @param opts
|
|
3691
|
+
*/
|
|
3692
|
+
async createAuthorizationRequestUrl(opts) {
|
|
3693
|
+
if (!this._state.authorizationURL) {
|
|
3694
|
+
this.calculatePKCEOpts(opts?.pkce);
|
|
3695
|
+
this._state.authorizationRequestOpts = this.syncAuthorizationRequestOpts(opts?.authorizationRequest);
|
|
3696
|
+
if (!this._state.authorizationRequestOpts) {
|
|
3697
|
+
throw Error(`No Authorization Request options present or provided in this call`);
|
|
3698
|
+
}
|
|
3699
|
+
if (this._state.endpointMetadata?.credentialIssuerMetadata && "authorization_endpoint" in this._state.endpointMetadata.credentialIssuerMetadata) {
|
|
3700
|
+
this._state.endpointMetadata.authorization_endpoint = this._state.endpointMetadata.credentialIssuerMetadata.authorization_endpoint;
|
|
3701
|
+
}
|
|
3702
|
+
this._state.authorizationURL = await createAuthorizationRequestUrl({
|
|
3703
|
+
pkce: this._state.pkce,
|
|
3704
|
+
endpointMetadata: this.endpointMetadata,
|
|
3705
|
+
authorizationRequest: this._state.authorizationRequestOpts,
|
|
3706
|
+
credentialOffer: this.credentialOffer,
|
|
3707
|
+
credentialConfigurationSupported: this.getCredentialsSupported(),
|
|
3708
|
+
version: this.version()
|
|
3709
|
+
});
|
|
3710
|
+
}
|
|
3711
|
+
return this._state.authorizationURL;
|
|
3712
|
+
}
|
|
3713
|
+
async retrieveServerMetadata() {
|
|
3714
|
+
this.assertIssuerData();
|
|
3715
|
+
if (!this._state.endpointMetadata) {
|
|
3716
|
+
if (this.credentialOffer) {
|
|
3717
|
+
this._state.endpointMetadata = await MetadataClientV1_0_13.retrieveAllMetadataFromCredentialOffer(this.credentialOffer);
|
|
3718
|
+
} else if (this._state.credentialIssuer) {
|
|
3719
|
+
this._state.endpointMetadata = await MetadataClientV1_0_13.retrieveAllMetadata(this._state.credentialIssuer);
|
|
3720
|
+
} else {
|
|
3721
|
+
throw Error(`Cannot retrieve issuer metadata without either a credential offer, or issuer value`);
|
|
3722
|
+
}
|
|
3723
|
+
}
|
|
3724
|
+
return this.endpointMetadata;
|
|
3725
|
+
}
|
|
3726
|
+
calculatePKCEOpts(pkce) {
|
|
3727
|
+
this._state.pkce = generateMissingPKCEOpts({
|
|
3728
|
+
...this._state.pkce,
|
|
3729
|
+
...pkce
|
|
3730
|
+
});
|
|
3731
|
+
}
|
|
3732
|
+
async acquireAuthorizationChallengeCode(opts) {
|
|
3733
|
+
const response = await acquireAuthorizationChallengeAuthCode({
|
|
3734
|
+
metadata: this.endpointMetadata,
|
|
3735
|
+
credentialIssuer: this.getIssuer(),
|
|
3736
|
+
clientId: this._state.clientId ?? this._state.authorizationRequestOpts?.clientId,
|
|
3737
|
+
...opts
|
|
3738
|
+
});
|
|
3739
|
+
if (response.errorBody) {
|
|
3740
|
+
debug14(`Authorization code error:\r
|
|
3741
|
+
${JSON.stringify(response.errorBody)}`);
|
|
3742
|
+
const error = response.errorBody;
|
|
3743
|
+
return Promise.reject(error);
|
|
3744
|
+
} else if (!response.successBody) {
|
|
3745
|
+
debug14(`Authorization code error. No success body`);
|
|
3746
|
+
return Promise.reject(Error(`Retrieving an authorization code token from ${this._state.endpointMetadata?.authorization_challenge_endpoint} for issuer ${this.getIssuer()} failed as there was no success response body`));
|
|
3747
|
+
}
|
|
3748
|
+
return {
|
|
3749
|
+
...response.successBody
|
|
3750
|
+
};
|
|
3751
|
+
}
|
|
3752
|
+
async acquireAccessToken(opts) {
|
|
3753
|
+
const { pin, clientId = this._state.clientId ?? this._state.authorizationRequestOpts?.clientId } = opts ?? {};
|
|
3754
|
+
let { redirectUri } = opts ?? {};
|
|
3755
|
+
const code = this.getAuthorizationCode(opts?.authorizationResponse, opts?.code);
|
|
3756
|
+
if (opts?.codeVerifier) {
|
|
3757
|
+
this._state.pkce.codeVerifier = opts.codeVerifier;
|
|
3758
|
+
}
|
|
3759
|
+
this.assertIssuerData();
|
|
3760
|
+
const asOpts = {
|
|
3761
|
+
...opts?.asOpts
|
|
3762
|
+
};
|
|
3763
|
+
const kid = asOpts.clientOpts?.kid ?? this._state.kid ?? this._state.authorizationRequestOpts?.requestObjectOpts?.kid;
|
|
3764
|
+
const clientAssertionType = asOpts.clientOpts?.clientAssertionType ?? (kid && clientId && typeof asOpts.clientOpts?.signCallbacks?.signCallback === "function" ? "urn:ietf:params:oauth:client-assertion-type:jwt-bearer" : void 0);
|
|
3765
|
+
if (this.isEBSI() || clientId && kid) {
|
|
3766
|
+
if (!clientId) {
|
|
3767
|
+
throw Error(`Client id expected for EBSI`);
|
|
3768
|
+
}
|
|
3769
|
+
asOpts.clientOpts = {
|
|
3770
|
+
...asOpts.clientOpts,
|
|
3771
|
+
clientId,
|
|
3772
|
+
...kid && {
|
|
3773
|
+
kid
|
|
3774
|
+
},
|
|
3775
|
+
...clientAssertionType && {
|
|
3776
|
+
clientAssertionType
|
|
3777
|
+
},
|
|
3778
|
+
signCallbacks: asOpts.clientOpts?.signCallbacks ?? this._state.authorizationRequestOpts?.requestObjectOpts?.signCallbacks
|
|
3779
|
+
};
|
|
3780
|
+
}
|
|
3781
|
+
if (clientId) {
|
|
3782
|
+
this._state.clientId = clientId;
|
|
3783
|
+
if (!asOpts.clientOpts) {
|
|
3784
|
+
asOpts.clientOpts = {
|
|
3785
|
+
clientId
|
|
3786
|
+
};
|
|
3787
|
+
}
|
|
3788
|
+
asOpts.clientOpts.clientId = clientId;
|
|
3789
|
+
}
|
|
3790
|
+
if (!this._state.accessTokenResponse) {
|
|
3791
|
+
const accessTokenClient = new AccessTokenClient();
|
|
3792
|
+
if (redirectUri && redirectUri !== this._state.authorizationRequestOpts?.redirectUri) {
|
|
3793
|
+
console.log(`Redirect URI mismatch between access-token (${redirectUri}) and authorization request (${this._state.authorizationRequestOpts?.redirectUri}). According to the specification that is not allowed.`);
|
|
3794
|
+
}
|
|
3795
|
+
if (this._state.authorizationRequestOpts?.redirectUri && !redirectUri) {
|
|
3796
|
+
redirectUri = this._state.authorizationRequestOpts.redirectUri;
|
|
3797
|
+
}
|
|
3798
|
+
const response = await accessTokenClient.acquireAccessToken({
|
|
3799
|
+
credentialOffer: this.credentialOffer,
|
|
3800
|
+
metadata: this.endpointMetadata,
|
|
3801
|
+
credentialIssuer: this.getIssuer(),
|
|
3802
|
+
pin,
|
|
3803
|
+
...!this._state.pkce.disabled && {
|
|
3804
|
+
codeVerifier: this._state.pkce.codeVerifier
|
|
3805
|
+
},
|
|
3806
|
+
code,
|
|
3807
|
+
redirectUri,
|
|
3808
|
+
asOpts,
|
|
3809
|
+
...opts?.createDPoPOpts && {
|
|
3810
|
+
createDPoPOpts: opts.createDPoPOpts
|
|
3811
|
+
},
|
|
3812
|
+
...opts?.additionalRequestParams && {
|
|
3813
|
+
additionalParams: opts.additionalRequestParams
|
|
3814
|
+
}
|
|
3815
|
+
});
|
|
3816
|
+
if (response.errorBody) {
|
|
3817
|
+
debug14(`Access token error:\r
|
|
3818
|
+
${JSON.stringify(response.errorBody)}`);
|
|
3819
|
+
throw Error(`Retrieving an access token from ${this._state.endpointMetadata?.token_endpoint} for issuer ${this.getIssuer()} failed with status: ${response.origResponse.status}`);
|
|
3820
|
+
} else if (!response.successBody) {
|
|
3821
|
+
debug14(`Access token error. No success body`);
|
|
3822
|
+
throw Error(`Retrieving an access token from ${this._state.endpointMetadata?.token_endpoint} for issuer ${this.getIssuer()} failed as there was no success response body`);
|
|
3823
|
+
}
|
|
3824
|
+
this._state.accessTokenResponse = response.successBody;
|
|
3825
|
+
this._state.dpopResponseParams = response.params;
|
|
3826
|
+
this._state.accessToken = response.successBody.access_token;
|
|
3827
|
+
}
|
|
3828
|
+
return {
|
|
3829
|
+
...this.accessTokenResponse,
|
|
3830
|
+
...this.dpopResponseParams && {
|
|
3831
|
+
params: this.dpopResponseParams
|
|
3832
|
+
}
|
|
3833
|
+
};
|
|
3834
|
+
}
|
|
3835
|
+
async acquireCredentialsWithoutProof(args) {
|
|
3836
|
+
return await this.acquireCredentialsImpl(args);
|
|
3837
|
+
}
|
|
3838
|
+
async acquireCredentials(args) {
|
|
3839
|
+
return await this.acquireCredentialsImpl(args);
|
|
3840
|
+
}
|
|
3841
|
+
async acquireCredentialsImpl({ credentialIdentifier, credentialTypes, context, proofCallbacks, format, kid, jwk, alg, jti, deferredCredentialAwait, deferredCredentialIntervalInMS, createDPoPOpts }) {
|
|
3842
|
+
if ([
|
|
3843
|
+
jwk,
|
|
3844
|
+
kid
|
|
3845
|
+
].filter((v) => v !== void 0).length > 1) {
|
|
3846
|
+
throw new Error(import_oid4vci_common24.KID_JWK_X5C_ERROR + `. jwk: ${jwk !== void 0}, kid: ${kid !== void 0}`);
|
|
3847
|
+
}
|
|
3848
|
+
if (alg) this._state.alg = alg;
|
|
3849
|
+
if (jwk) this._state.jwk = jwk;
|
|
3850
|
+
if (kid) this._state.kid = kid;
|
|
3851
|
+
const requestBuilder = this.credentialOffer ? CredentialRequestClientBuilderV1_0_13.fromCredentialOffer({
|
|
3852
|
+
credentialOffer: this.credentialOffer,
|
|
3853
|
+
metadata: this.endpointMetadata
|
|
3854
|
+
}) : CredentialRequestClientBuilderV1_0_13.fromCredentialIssuer({
|
|
3855
|
+
credentialIssuer: this.getIssuer(),
|
|
3856
|
+
credentialIdentifier,
|
|
3857
|
+
metadata: this.endpointMetadata,
|
|
3858
|
+
version: this.version()
|
|
3859
|
+
});
|
|
3860
|
+
const issuerState = this.issuerSupportedFlowTypes().includes(import_oid4vci_common24.AuthzFlowType.AUTHORIZATION_CODE_FLOW) && this._state.authorizationCodeResponse && !this.accessTokenResponse?.c_nonce && this._state.credentialOffer?.issuerState ? this._state.credentialOffer.issuerState : void 0;
|
|
3861
|
+
requestBuilder.withIssuerState(issuerState);
|
|
3862
|
+
requestBuilder.withTokenFromResponse(this.accessTokenResponse);
|
|
3863
|
+
requestBuilder.withDeferredCredentialAwait(deferredCredentialAwait ?? false, deferredCredentialIntervalInMS);
|
|
3864
|
+
let subjectIssuance;
|
|
3865
|
+
if (this.endpointMetadata?.credentialIssuerMetadata) {
|
|
3866
|
+
const metadata = this.endpointMetadata.credentialIssuerMetadata;
|
|
3867
|
+
const types = credentialTypes ? Array.isArray(credentialTypes) ? credentialTypes : [
|
|
3868
|
+
credentialTypes
|
|
3869
|
+
] : void 0;
|
|
3870
|
+
if (credentialIdentifier) {
|
|
3871
|
+
if (typeof metadata.credential_configurations_supported !== "object") {
|
|
3872
|
+
throw Error(`Credentials_supported should be an object, current ${typeof metadata.credential_configurations_supported} when credential_identifier is used`);
|
|
3873
|
+
}
|
|
3874
|
+
const credentialsSupported = metadata.credential_configurations_supported;
|
|
3875
|
+
if (!credentialsSupported || !credentialsSupported[credentialIdentifier]) {
|
|
3876
|
+
throw new Error(`Credential type ${credentialIdentifier} is not supported by issuer ${this.getIssuer()}`);
|
|
3877
|
+
}
|
|
3878
|
+
} else if (!types) {
|
|
3879
|
+
throw Error(`If no credential_identifier is used, we expect types`);
|
|
3880
|
+
} else if (metadata.credentials_supported && Array.isArray(metadata.credentials_supported)) {
|
|
3881
|
+
let typeSupported = false;
|
|
3882
|
+
metadata.credentials_supported.forEach((supportedCredential) => {
|
|
3883
|
+
const subTypes = (0, import_oid4vci_common24.getTypesFromCredentialSupported)(supportedCredential);
|
|
3884
|
+
if (subTypes.every((t, i) => types[i] === t) || types.length === 1 && (types[0] === supportedCredential.id || subTypes.includes(types[0]))) {
|
|
3885
|
+
typeSupported = true;
|
|
3886
|
+
if (supportedCredential.credential_subject_issuance) {
|
|
3887
|
+
subjectIssuance = {
|
|
3888
|
+
credential_subject_issuance: supportedCredential.credential_subject_issuance
|
|
3889
|
+
};
|
|
3890
|
+
}
|
|
3891
|
+
}
|
|
3892
|
+
});
|
|
3893
|
+
if (!typeSupported) {
|
|
3894
|
+
console.log(`Not all credential types ${JSON.stringify(credentialTypes)} are present in metadata for ${this.getIssuer()}`);
|
|
3895
|
+
}
|
|
3896
|
+
} else if (metadata.credential_configurations_supported && typeof metadata.credential_configurations_supported === "object") {
|
|
3897
|
+
let typeSupported = false;
|
|
3898
|
+
Object.values(metadata.credential_configurations_supported).forEach((supportedCredential) => {
|
|
3899
|
+
const subTypes = (0, import_oid4vci_common24.getTypesFromCredentialSupported)(supportedCredential);
|
|
3900
|
+
if (subTypes.every((t, i) => types[i] === t) || types.length === 1 && (types[0] === supportedCredential.id || subTypes.includes(types[0]))) {
|
|
3901
|
+
typeSupported = true;
|
|
3902
|
+
}
|
|
3903
|
+
});
|
|
3904
|
+
if (!typeSupported) {
|
|
3905
|
+
throw Error(`Not all credential types ${JSON.stringify(credentialTypes)} are supported by issuer ${this.getIssuer()}`);
|
|
3906
|
+
}
|
|
3907
|
+
}
|
|
3908
|
+
}
|
|
3909
|
+
if (subjectIssuance) {
|
|
3910
|
+
requestBuilder.withSubjectIssuance(subjectIssuance);
|
|
3911
|
+
}
|
|
3912
|
+
const credentialRequestClient = requestBuilder.build();
|
|
3913
|
+
let proofBuilder;
|
|
3914
|
+
if (proofCallbacks) {
|
|
3915
|
+
proofBuilder = ProofOfPossessionBuilder.fromAccessTokenResponse({
|
|
3916
|
+
accessTokenResponse: this.accessTokenResponse,
|
|
3917
|
+
callbacks: proofCallbacks,
|
|
3918
|
+
version: this.version()
|
|
3919
|
+
}).withIssuer(this.getIssuer()).withAlg(this.alg);
|
|
3920
|
+
if (this._state.jwk) {
|
|
3921
|
+
proofBuilder.withJWK(this._state.jwk);
|
|
3922
|
+
}
|
|
3923
|
+
if (this._state.kid) {
|
|
3924
|
+
proofBuilder.withKid(this._state.kid);
|
|
3925
|
+
}
|
|
3926
|
+
if (this.clientId) {
|
|
3927
|
+
proofBuilder.withClientId(this.clientId);
|
|
3928
|
+
}
|
|
3929
|
+
if (jti) {
|
|
3930
|
+
proofBuilder.withJti(jti);
|
|
3931
|
+
}
|
|
3932
|
+
}
|
|
3933
|
+
const request = proofBuilder ? await credentialRequestClient.createCredentialRequest({
|
|
3934
|
+
proofInput: proofBuilder,
|
|
3935
|
+
credentialTypes,
|
|
3936
|
+
context,
|
|
3937
|
+
format,
|
|
3938
|
+
version: this.version(),
|
|
3939
|
+
credentialIdentifier,
|
|
3940
|
+
subjectIssuance
|
|
3941
|
+
}) : await credentialRequestClient.createCredentialRequestWithoutProof({
|
|
3942
|
+
credentialTypes,
|
|
3943
|
+
context,
|
|
3944
|
+
format,
|
|
3945
|
+
version: this.version(),
|
|
3946
|
+
credentialIdentifier,
|
|
3947
|
+
subjectIssuance
|
|
3948
|
+
});
|
|
3949
|
+
const response = await credentialRequestClient.acquireCredentialsUsingRequest(request, createDPoPOpts);
|
|
3950
|
+
this._state.dpopResponseParams = response.params;
|
|
3951
|
+
if (response.errorBody) {
|
|
3952
|
+
debug14(`Credential request error:\r
|
|
3953
|
+
${JSON.stringify(response.errorBody)}`);
|
|
3954
|
+
throw Error(`Retrieving a credential from ${this._state.endpointMetadata?.credential_endpoint} for issuer ${this.getIssuer()} failed with status: ${response.origResponse.status}`);
|
|
3955
|
+
} else if (!response.successBody) {
|
|
3956
|
+
debug14(`Credential request error. No success body`);
|
|
3957
|
+
throw Error(`Retrieving a credential from ${this._state.endpointMetadata?.credential_endpoint} for issuer ${this.getIssuer()} failed as there was no success response body`);
|
|
3958
|
+
}
|
|
3959
|
+
return {
|
|
3960
|
+
...response.successBody,
|
|
3961
|
+
...this.dpopResponseParams && {
|
|
3962
|
+
params: this.dpopResponseParams
|
|
3963
|
+
},
|
|
3964
|
+
access_token: response.access_token
|
|
3965
|
+
};
|
|
3966
|
+
}
|
|
3967
|
+
async exportState() {
|
|
3968
|
+
return JSON.stringify(this._state);
|
|
3969
|
+
}
|
|
3970
|
+
getCredentialsSupported(format) {
|
|
3971
|
+
return (0, import_oid4vci_common24.getSupportedCredentials)({
|
|
3972
|
+
issuerMetadata: this.endpointMetadata.credentialIssuerMetadata,
|
|
3973
|
+
version: this.version(),
|
|
3974
|
+
format,
|
|
3975
|
+
types: void 0
|
|
3976
|
+
});
|
|
3977
|
+
}
|
|
3978
|
+
async sendNotification(credentialRequestOpts, request, accessToken) {
|
|
3979
|
+
return sendNotification(credentialRequestOpts, request, accessToken ?? this._state.accessToken ?? this._state.accessTokenResponse?.access_token);
|
|
3980
|
+
}
|
|
3981
|
+
/* getCredentialOfferTypes(): string[][] {
|
|
3982
|
+
if (!this.credentialOffer) {
|
|
3983
|
+
return [];
|
|
3984
|
+
} else if (this.credentialOffer.version < OpenId4VCIVersion.VER_1_0_11) {
|
|
3985
|
+
const orig = this.credentialOffer.original_credential_offer as CredentialOfferPayloadV1_0_08;
|
|
3986
|
+
const types: string[] = typeof orig.credential_type === 'string' ? [orig.credential_type] : orig.credential_type;
|
|
3987
|
+
const result: string[][] = [];
|
|
3988
|
+
result[0] = types;
|
|
3989
|
+
return result;
|
|
3990
|
+
} else {
|
|
3991
|
+
return this.credentialOffer.credential_offer.credentials.map((c) => {
|
|
3992
|
+
if (typeof c === 'string') {
|
|
3993
|
+
return [c];
|
|
3994
|
+
} else if ('types' in c) {
|
|
3995
|
+
return c.types;
|
|
3996
|
+
} else if ('vct' in c) {
|
|
3997
|
+
return [c.vct];
|
|
3998
|
+
} else {
|
|
3999
|
+
return c.credential_definition.types;
|
|
4000
|
+
}
|
|
4001
|
+
});
|
|
4002
|
+
}
|
|
4003
|
+
}*/
|
|
4004
|
+
issuerSupportedFlowTypes() {
|
|
4005
|
+
return this.credentialOffer?.supportedFlows ?? (this._state.endpointMetadata?.credentialIssuerMetadata?.authorization_endpoint ? [
|
|
4006
|
+
import_oid4vci_common24.AuthzFlowType.AUTHORIZATION_CODE_FLOW
|
|
4007
|
+
] : []);
|
|
4008
|
+
}
|
|
4009
|
+
isFlowTypeSupported(flowType) {
|
|
4010
|
+
return this.issuerSupportedFlowTypes().includes(flowType);
|
|
4011
|
+
}
|
|
4012
|
+
hasAuthorizationURL() {
|
|
4013
|
+
return !!this.authorizationURL;
|
|
4014
|
+
}
|
|
4015
|
+
get authorizationURL() {
|
|
4016
|
+
return this._state.authorizationURL;
|
|
4017
|
+
}
|
|
4018
|
+
get credentialOffer() {
|
|
4019
|
+
return this._state.credentialOffer;
|
|
4020
|
+
}
|
|
4021
|
+
version() {
|
|
4022
|
+
return this.credentialOffer?.version ?? import_oid4vci_common24.OpenId4VCIVersion.VER_1_0_13;
|
|
4023
|
+
}
|
|
4024
|
+
get endpointMetadata() {
|
|
4025
|
+
this.assertServerMetadata();
|
|
4026
|
+
return this._state.endpointMetadata;
|
|
4027
|
+
}
|
|
4028
|
+
get kid() {
|
|
4029
|
+
this.assertIssuerData();
|
|
4030
|
+
if (!this._state.kid) {
|
|
4031
|
+
throw new Error("No value for kid is supplied");
|
|
4032
|
+
}
|
|
4033
|
+
return this._state.kid;
|
|
4034
|
+
}
|
|
4035
|
+
get alg() {
|
|
4036
|
+
this.assertIssuerData();
|
|
4037
|
+
if (!this._state.alg) {
|
|
4038
|
+
throw new Error("No value for alg is supplied");
|
|
4039
|
+
}
|
|
4040
|
+
return this._state.alg;
|
|
4041
|
+
}
|
|
4042
|
+
set clientId(value) {
|
|
4043
|
+
this._state.clientId = value;
|
|
4044
|
+
}
|
|
4045
|
+
get clientId() {
|
|
4046
|
+
return this._state.clientId;
|
|
4047
|
+
}
|
|
4048
|
+
hasAccessTokenResponse() {
|
|
4049
|
+
return !!this._state.accessTokenResponse;
|
|
4050
|
+
}
|
|
4051
|
+
get accessTokenResponse() {
|
|
4052
|
+
this.assertAccessToken();
|
|
4053
|
+
return this._state.accessTokenResponse;
|
|
4054
|
+
}
|
|
4055
|
+
get dpopResponseParams() {
|
|
4056
|
+
return this._state.dpopResponseParams;
|
|
4057
|
+
}
|
|
4058
|
+
getIssuer() {
|
|
4059
|
+
this.assertIssuerData();
|
|
4060
|
+
return this._state.credentialIssuer;
|
|
4061
|
+
}
|
|
4062
|
+
getAccessTokenEndpoint() {
|
|
4063
|
+
this.assertIssuerData();
|
|
4064
|
+
return this.endpointMetadata ? this.endpointMetadata.token_endpoint : AccessTokenClient.determineTokenURL({
|
|
4065
|
+
issuerOpts: {
|
|
4066
|
+
issuer: this.getIssuer()
|
|
4067
|
+
}
|
|
4068
|
+
});
|
|
4069
|
+
}
|
|
4070
|
+
getCredentialEndpoint() {
|
|
4071
|
+
this.assertIssuerData();
|
|
4072
|
+
return this.endpointMetadata ? this.endpointMetadata.credential_endpoint : `${this.getIssuer()}/credential`;
|
|
4073
|
+
}
|
|
4074
|
+
hasDeferredCredentialEndpoint() {
|
|
4075
|
+
return !!this.getAccessTokenEndpoint();
|
|
4076
|
+
}
|
|
4077
|
+
getDeferredCredentialEndpoint() {
|
|
4078
|
+
this.assertIssuerData();
|
|
4079
|
+
return this.endpointMetadata ? this.endpointMetadata.credential_endpoint : `${this.getIssuer()}/credential`;
|
|
4080
|
+
}
|
|
4081
|
+
/**
|
|
4082
|
+
* Too bad we need a method like this, but EBSI is not exposing metadata
|
|
4083
|
+
*/
|
|
4084
|
+
isEBSI() {
|
|
4085
|
+
const credentialOffer = this.credentialOffer?.credential_offer;
|
|
4086
|
+
if (credentialOffer?.credential_configuration_ids) {
|
|
4087
|
+
const credentialConfigurations = this.endpointMetadata.credentialIssuerMetadata?.credential_configurations_supported;
|
|
4088
|
+
if (credentialConfigurations) {
|
|
4089
|
+
const isEBSITrustFramework = credentialOffer.credential_configuration_ids.map((id) => credentialConfigurations[id]).filter((config) => (
|
|
4090
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
4091
|
+
// @ts-ignore
|
|
4092
|
+
config !== void 0 && "trust_framework" in config && "name" in config.trust_framework
|
|
4093
|
+
)).some((config) => config.trust_framework.name.includes("ebsi"));
|
|
4094
|
+
if (isEBSITrustFramework) {
|
|
4095
|
+
return true;
|
|
4096
|
+
}
|
|
4097
|
+
}
|
|
4098
|
+
}
|
|
4099
|
+
return this.clientId?.includes("ebsi") || this._state.kid?.includes("did:ebsi:") || this.getIssuer().includes("ebsi") || this.endpointMetadata.credentialIssuerMetadata?.authorization_endpoint?.includes("ebsi.eu") || this.endpointMetadata.credentialIssuerMetadata?.authorization_server?.includes("ebsi.eu");
|
|
4100
|
+
}
|
|
4101
|
+
assertIssuerData() {
|
|
4102
|
+
if (!this._state.credentialIssuer) {
|
|
4103
|
+
throw Error(`No credential issuer value present`);
|
|
4104
|
+
} else if (!this._state.credentialOffer && this._state.endpointMetadata && this.issuerSupportedFlowTypes().length === 0) {
|
|
4105
|
+
throw Error(`No issuance initiation or credential offer present`);
|
|
4106
|
+
}
|
|
4107
|
+
}
|
|
4108
|
+
assertServerMetadata() {
|
|
4109
|
+
if (!this._state.endpointMetadata) {
|
|
4110
|
+
throw Error("No server metadata");
|
|
4111
|
+
}
|
|
4112
|
+
}
|
|
4113
|
+
assertAccessToken() {
|
|
4114
|
+
if (!this._state.accessTokenResponse) {
|
|
4115
|
+
throw Error(`No access token present`);
|
|
4116
|
+
}
|
|
4117
|
+
}
|
|
4118
|
+
syncAuthorizationRequestOpts(opts) {
|
|
4119
|
+
let authorizationRequestOpts = {
|
|
4120
|
+
...this._state?.authorizationRequestOpts,
|
|
4121
|
+
...opts
|
|
4122
|
+
};
|
|
4123
|
+
if (!authorizationRequestOpts) {
|
|
4124
|
+
authorizationRequestOpts = {
|
|
4125
|
+
redirectUri: `${import_oid4vci_common24.DefaultURISchemes.CREDENTIAL_OFFER}://`
|
|
4126
|
+
};
|
|
4127
|
+
}
|
|
4128
|
+
const clientId = authorizationRequestOpts.clientId ?? this._state.clientId;
|
|
4129
|
+
this._state.clientId = clientId;
|
|
4130
|
+
authorizationRequestOpts.clientId = clientId;
|
|
4131
|
+
return authorizationRequestOpts;
|
|
4132
|
+
}
|
|
4133
|
+
getAuthorizationCode = /* @__PURE__ */ __name((authorizationResponse, code) => {
|
|
4134
|
+
if (authorizationResponse) {
|
|
4135
|
+
this._state.authorizationCodeResponse = {
|
|
4136
|
+
...(0, import_oid4vci_common24.toAuthorizationResponsePayload)(authorizationResponse)
|
|
4137
|
+
};
|
|
4138
|
+
} else if (code) {
|
|
4139
|
+
this._state.authorizationCodeResponse = {
|
|
4140
|
+
code
|
|
4141
|
+
};
|
|
4142
|
+
}
|
|
4143
|
+
return this._state.authorizationCodeResponse?.code ?? this._state.authorizationCodeResponse?.authorization_code;
|
|
4144
|
+
}, "getAuthorizationCode");
|
|
4145
|
+
};
|
|
4146
|
+
|
|
4147
|
+
// lib/OpenID4VCIClientV1_0_11.ts
|
|
4148
|
+
var import_oid4vci_common25 = require("@sphereon/oid4vci-common");
|
|
4149
|
+
var import_debug15 = __toESM(require("debug"), 1);
|
|
4150
|
+
var debug15 = (0, import_debug15.default)("sphereon:oid4vci");
|
|
4151
|
+
var OpenID4VCIClientV1_0_11 = class _OpenID4VCIClientV1_0_11 {
|
|
4152
|
+
static {
|
|
4153
|
+
__name(this, "OpenID4VCIClientV1_0_11");
|
|
4154
|
+
}
|
|
4155
|
+
_state;
|
|
4156
|
+
constructor({ credentialOffer, clientId, kid, alg, credentialIssuer, pkce, authorizationRequest, jwk, endpointMetadata, accessTokenResponse, authorizationRequestOpts, authorizationCodeResponse, authorizationURL }) {
|
|
4157
|
+
const issuer = credentialIssuer ?? (credentialOffer ? (0, import_oid4vci_common25.getIssuerFromCredentialOfferPayload)(credentialOffer.credential_offer) : void 0);
|
|
4158
|
+
if (!issuer) {
|
|
4159
|
+
throw Error("No credential issuer supplied or deduced from offer");
|
|
4160
|
+
}
|
|
4161
|
+
this._state = {
|
|
4162
|
+
credentialOffer,
|
|
4163
|
+
credentialIssuer: issuer,
|
|
4164
|
+
kid,
|
|
4165
|
+
alg,
|
|
4166
|
+
// TODO: We need to refactor this and always explicitly call createAuthorizationRequestUrl, so we can have a credential selection first and use the kid as a default for the client id
|
|
4167
|
+
clientId: clientId ?? (credentialOffer && (0, import_oid4vci_common25.getClientIdFromCredentialOfferPayload)(credentialOffer.credential_offer)) ?? kid?.split("#")[0],
|
|
4168
|
+
pkce: {
|
|
4169
|
+
disabled: false,
|
|
4170
|
+
codeChallengeMethod: import_oid4vci_common25.CodeChallengeMethod.S256,
|
|
4171
|
+
...pkce
|
|
4172
|
+
},
|
|
4173
|
+
authorizationRequestOpts,
|
|
4174
|
+
authorizationCodeResponse,
|
|
4175
|
+
jwk,
|
|
4176
|
+
endpointMetadata,
|
|
4177
|
+
accessTokenResponse,
|
|
4178
|
+
authorizationURL
|
|
4179
|
+
};
|
|
4180
|
+
if (!this._state.authorizationRequestOpts) {
|
|
4181
|
+
this._state.authorizationRequestOpts = this.syncAuthorizationRequestOpts(authorizationRequest);
|
|
4182
|
+
}
|
|
4183
|
+
debug15(`Authorization req options: ${JSON.stringify(this._state.authorizationRequestOpts, null, 2)}`);
|
|
4184
|
+
}
|
|
4185
|
+
static async fromCredentialIssuer({ kid, alg, retrieveServerMetadata, clientId, credentialIssuer, pkce, authorizationRequest, createAuthorizationRequestURL }) {
|
|
4186
|
+
const client = new _OpenID4VCIClientV1_0_11({
|
|
4187
|
+
kid,
|
|
4188
|
+
alg,
|
|
4189
|
+
clientId: clientId ?? authorizationRequest?.clientId,
|
|
4190
|
+
credentialIssuer,
|
|
4191
|
+
pkce,
|
|
4192
|
+
authorizationRequest
|
|
4193
|
+
});
|
|
4194
|
+
if (retrieveServerMetadata === void 0 || retrieveServerMetadata) {
|
|
4195
|
+
await client.retrieveServerMetadata();
|
|
4196
|
+
}
|
|
4197
|
+
if (createAuthorizationRequestURL === void 0 || createAuthorizationRequestURL) {
|
|
4198
|
+
await client.createAuthorizationRequestUrl({
|
|
4199
|
+
authorizationRequest,
|
|
4200
|
+
pkce
|
|
4201
|
+
});
|
|
4202
|
+
}
|
|
4203
|
+
return client;
|
|
4204
|
+
}
|
|
4205
|
+
static async fromState({ state }) {
|
|
4206
|
+
const clientState = typeof state === "string" ? JSON.parse(state) : state;
|
|
4207
|
+
return new _OpenID4VCIClientV1_0_11(clientState);
|
|
4208
|
+
}
|
|
4209
|
+
static async fromURI({ uri, kid, alg, retrieveServerMetadata, clientId, pkce, createAuthorizationRequestURL, authorizationRequest, resolveOfferUri }) {
|
|
4210
|
+
const credentialOfferClient = await CredentialOfferClientV1_0_11.fromURI(uri, {
|
|
4211
|
+
resolve: resolveOfferUri
|
|
4212
|
+
});
|
|
4213
|
+
const client = new _OpenID4VCIClientV1_0_11({
|
|
4214
|
+
credentialOffer: credentialOfferClient,
|
|
4215
|
+
kid,
|
|
4216
|
+
alg,
|
|
4217
|
+
clientId: clientId ?? authorizationRequest?.clientId ?? credentialOfferClient.clientId,
|
|
4218
|
+
pkce,
|
|
4219
|
+
authorizationRequest
|
|
4220
|
+
});
|
|
4221
|
+
if (retrieveServerMetadata === void 0 || retrieveServerMetadata) {
|
|
4222
|
+
await client.retrieveServerMetadata();
|
|
4223
|
+
}
|
|
4224
|
+
if (credentialOfferClient.supportedFlows.includes(import_oid4vci_common25.AuthzFlowType.AUTHORIZATION_CODE_FLOW) && (createAuthorizationRequestURL === void 0 || createAuthorizationRequestURL)) {
|
|
4225
|
+
await client.createAuthorizationRequestUrl({
|
|
4226
|
+
authorizationRequest,
|
|
4227
|
+
pkce
|
|
4228
|
+
});
|
|
4229
|
+
debug15(`Authorization Request URL: ${client._state.authorizationURL}`);
|
|
4230
|
+
}
|
|
4231
|
+
return client;
|
|
4232
|
+
}
|
|
4233
|
+
/**
|
|
4234
|
+
* Allows you to create an Authorization Request URL when using an Authorization Code flow. This URL needs to be accessed using the front channel (browser)
|
|
4235
|
+
*
|
|
4236
|
+
* The Identity provider would present a login screen typically; after you authenticated, it would redirect to the provided redirectUri; which can be same device or cross-device
|
|
4237
|
+
* @param opts
|
|
4238
|
+
*/
|
|
4239
|
+
async createAuthorizationRequestUrl(opts) {
|
|
4240
|
+
if (!this._state.authorizationURL) {
|
|
4241
|
+
this.calculatePKCEOpts(opts?.pkce);
|
|
4242
|
+
this._state.authorizationRequestOpts = this.syncAuthorizationRequestOpts(opts?.authorizationRequest);
|
|
4243
|
+
if (!this._state.authorizationRequestOpts) {
|
|
4244
|
+
throw Error(`No Authorization Request options present or provided in this call`);
|
|
4245
|
+
}
|
|
4246
|
+
if (this._state.endpointMetadata?.credentialIssuerMetadata && "authorization_endpoint" in this._state.endpointMetadata.credentialIssuerMetadata) {
|
|
4247
|
+
this._state.endpointMetadata.authorization_endpoint = this._state.endpointMetadata.credentialIssuerMetadata.authorization_endpoint;
|
|
4248
|
+
}
|
|
4249
|
+
this._state.authorizationURL = await createAuthorizationRequestUrlV1_0_11({
|
|
4250
|
+
pkce: this._state.pkce,
|
|
4251
|
+
endpointMetadata: this.endpointMetadata,
|
|
4252
|
+
authorizationRequest: this._state.authorizationRequestOpts,
|
|
4253
|
+
credentialOffer: this.credentialOffer,
|
|
4254
|
+
credentialsSupported: Object.values(this.getCredentialsSupported())
|
|
4255
|
+
});
|
|
4256
|
+
}
|
|
4257
|
+
return this._state.authorizationURL;
|
|
4258
|
+
}
|
|
4259
|
+
async retrieveServerMetadata() {
|
|
4260
|
+
this.assertIssuerData();
|
|
4261
|
+
if (!this._state.endpointMetadata) {
|
|
4262
|
+
if (this.credentialOffer) {
|
|
4263
|
+
this._state.endpointMetadata = await MetadataClientV1_0_11.retrieveAllMetadataFromCredentialOffer(this.credentialOffer);
|
|
4264
|
+
} else if (this._state.credentialIssuer) {
|
|
4265
|
+
this._state.endpointMetadata = await MetadataClientV1_0_11.retrieveAllMetadata(this._state.credentialIssuer);
|
|
4266
|
+
} else {
|
|
4267
|
+
throw Error(`Cannot retrieve issuer metadata without either a credential offer, or issuer value`);
|
|
4268
|
+
}
|
|
4269
|
+
}
|
|
4270
|
+
return this.endpointMetadata;
|
|
4271
|
+
}
|
|
4272
|
+
calculatePKCEOpts(pkce) {
|
|
4273
|
+
this._state.pkce = generateMissingPKCEOpts({
|
|
4274
|
+
...this._state.pkce,
|
|
4275
|
+
...pkce
|
|
4276
|
+
});
|
|
4277
|
+
}
|
|
4278
|
+
async acquireAuthorizationChallengeCode(opts) {
|
|
4279
|
+
const response = await acquireAuthorizationChallengeAuthCode({
|
|
4280
|
+
metadata: this.endpointMetadata,
|
|
4281
|
+
credentialIssuer: this.getIssuer(),
|
|
4282
|
+
clientId: this._state.clientId ?? this._state.authorizationRequestOpts?.clientId,
|
|
4283
|
+
...opts
|
|
4284
|
+
});
|
|
4285
|
+
if (response.errorBody) {
|
|
4286
|
+
debug15(`Authorization code error:\r
|
|
4287
|
+
${JSON.stringify(response.errorBody)}`);
|
|
4288
|
+
const error = response.errorBody;
|
|
4289
|
+
return Promise.reject(error);
|
|
4290
|
+
} else if (!response.successBody) {
|
|
4291
|
+
debug15(`Authorization code error. No success body`);
|
|
4292
|
+
return Promise.reject(Error(`Retrieving an authorization code token from ${this._state.endpointMetadata?.authorization_challenge_endpoint} for issuer ${this.getIssuer()} failed as there was no success response body`));
|
|
4293
|
+
}
|
|
4294
|
+
return {
|
|
4295
|
+
...response.successBody
|
|
4296
|
+
};
|
|
4297
|
+
}
|
|
4298
|
+
async acquireAccessToken(opts) {
|
|
4299
|
+
const { pin, clientId = this._state.clientId ?? this._state.authorizationRequestOpts?.clientId } = opts ?? {};
|
|
4300
|
+
let { redirectUri } = opts ?? {};
|
|
4301
|
+
const code = this.getAuthorizationCode(opts?.authorizationResponse, opts?.code);
|
|
4302
|
+
if (opts?.codeVerifier) {
|
|
4303
|
+
this._state.pkce.codeVerifier = opts.codeVerifier;
|
|
4304
|
+
}
|
|
4305
|
+
this.assertIssuerData();
|
|
4306
|
+
const asOpts = {
|
|
4307
|
+
...opts?.asOpts
|
|
4308
|
+
};
|
|
4309
|
+
if (clientId) {
|
|
4310
|
+
this._state.clientId = clientId;
|
|
4311
|
+
if (!asOpts.clientOpts) {
|
|
4312
|
+
asOpts.clientOpts = {
|
|
4313
|
+
clientId
|
|
4314
|
+
};
|
|
4315
|
+
}
|
|
4316
|
+
asOpts.clientOpts.clientId = clientId;
|
|
4317
|
+
}
|
|
4318
|
+
if (!this._state.accessTokenResponse) {
|
|
4319
|
+
const accessTokenClient = new AccessTokenClientV1_0_11();
|
|
4320
|
+
if (redirectUri && redirectUri !== this._state.authorizationRequestOpts?.redirectUri) {
|
|
4321
|
+
console.log(`Redirect URI mismatch between access-token (${redirectUri}) and authorization request (${this._state.authorizationRequestOpts?.redirectUri}). According to the specification that is not allowed.`);
|
|
4322
|
+
}
|
|
4323
|
+
if (this._state.authorizationRequestOpts?.redirectUri && !redirectUri) {
|
|
4324
|
+
redirectUri = this._state.authorizationRequestOpts.redirectUri;
|
|
4325
|
+
}
|
|
4326
|
+
const kid = asOpts.clientOpts?.kid ?? this._state.kid ?? this._state.authorizationRequestOpts?.requestObjectOpts?.kid;
|
|
4327
|
+
const clientAssertionType = asOpts.clientOpts?.clientAssertionType ?? (kid && clientId && typeof asOpts.clientOpts?.signCallbacks?.signCallback === "function" ? "urn:ietf:params:oauth:client-assertion-type:jwt-bearer" : void 0);
|
|
4328
|
+
if (this.isEBSI() || clientId && kid) {
|
|
4329
|
+
if (!clientId) {
|
|
4330
|
+
throw Error(`Client id expected for EBSI`);
|
|
4331
|
+
}
|
|
4332
|
+
asOpts.clientOpts = {
|
|
4333
|
+
...asOpts.clientOpts,
|
|
4334
|
+
clientId,
|
|
4335
|
+
...kid && {
|
|
4336
|
+
kid
|
|
4337
|
+
},
|
|
4338
|
+
...clientAssertionType && {
|
|
4339
|
+
clientAssertionType
|
|
4340
|
+
},
|
|
4341
|
+
signCallbacks: asOpts.clientOpts?.signCallbacks ?? this._state.authorizationRequestOpts?.requestObjectOpts?.signCallbacks
|
|
4342
|
+
};
|
|
4343
|
+
}
|
|
4344
|
+
const response = await accessTokenClient.acquireAccessToken({
|
|
4345
|
+
credentialOffer: this.credentialOffer,
|
|
4346
|
+
metadata: this.endpointMetadata,
|
|
4347
|
+
credentialIssuer: this.getIssuer(),
|
|
4348
|
+
pin,
|
|
4349
|
+
...!this._state.pkce.disabled && {
|
|
4350
|
+
codeVerifier: this._state.pkce.codeVerifier
|
|
4351
|
+
},
|
|
4352
|
+
code,
|
|
4353
|
+
redirectUri,
|
|
4354
|
+
asOpts,
|
|
4355
|
+
...opts?.createDPoPOpts && {
|
|
4356
|
+
createDPoPOpts: opts.createDPoPOpts
|
|
4357
|
+
},
|
|
4358
|
+
...opts?.additionalRequestParams && {
|
|
4359
|
+
additionalParams: opts.additionalRequestParams
|
|
4360
|
+
}
|
|
4361
|
+
});
|
|
4362
|
+
if (response.errorBody) {
|
|
4363
|
+
debug15(`Access token error:\r
|
|
4364
|
+
${JSON.stringify(response.errorBody)}`);
|
|
4365
|
+
throw Error(`Retrieving an access token from ${this._state.endpointMetadata?.token_endpoint} for issuer ${this.getIssuer()} failed with status: ${response.origResponse.status}`);
|
|
4366
|
+
} else if (!response.successBody) {
|
|
4367
|
+
debug15(`Access token error. No success body`);
|
|
4368
|
+
throw Error(`Retrieving an access token from ${this._state.endpointMetadata?.token_endpoint} for issuer ${this.getIssuer()} failed as there was no success response body`);
|
|
4369
|
+
}
|
|
4370
|
+
this._state.accessTokenResponse = response.successBody;
|
|
4371
|
+
this._state.dpopResponseParams = response.params;
|
|
4372
|
+
this._state.accessToken = response.successBody.access_token;
|
|
4373
|
+
}
|
|
4374
|
+
return {
|
|
4375
|
+
...this.accessTokenResponse,
|
|
4376
|
+
...this.dpopResponseParams && {
|
|
4377
|
+
params: this.dpopResponseParams
|
|
4378
|
+
}
|
|
4379
|
+
};
|
|
4380
|
+
}
|
|
4381
|
+
async acquireCredentials({ credentialTypes, context, proofCallbacks, format, kid, jwk, alg, jti, deferredCredentialAwait, deferredCredentialIntervalInMS, createDPoPOpts }) {
|
|
4382
|
+
if ([
|
|
4383
|
+
jwk,
|
|
4384
|
+
kid
|
|
4385
|
+
].filter((v) => v !== void 0).length > 1) {
|
|
4386
|
+
throw new Error(import_oid4vci_common25.KID_JWK_X5C_ERROR + `. jwk: ${jwk !== void 0}, kid: ${kid !== void 0}`);
|
|
4387
|
+
}
|
|
4388
|
+
if (alg) this._state.alg = alg;
|
|
4389
|
+
if (jwk) this._state.jwk = jwk;
|
|
4390
|
+
if (kid) this._state.kid = kid;
|
|
4391
|
+
const requestBuilder = this.credentialOffer ? CredentialRequestClientBuilderV1_0_11.fromCredentialOffer({
|
|
4392
|
+
credentialOffer: this.credentialOffer,
|
|
4393
|
+
metadata: this.endpointMetadata
|
|
4394
|
+
}) : CredentialRequestClientBuilderV1_0_11.fromCredentialIssuer({
|
|
4395
|
+
credentialIssuer: this.getIssuer(),
|
|
4396
|
+
credentialTypes,
|
|
4397
|
+
metadata: this.endpointMetadata,
|
|
4398
|
+
version: this.version()
|
|
4399
|
+
});
|
|
4400
|
+
requestBuilder.withTokenFromResponse(this.accessTokenResponse);
|
|
4401
|
+
requestBuilder.withDeferredCredentialAwait(deferredCredentialAwait ?? false, deferredCredentialIntervalInMS);
|
|
4402
|
+
if (this.endpointMetadata?.credentialIssuerMetadata) {
|
|
4403
|
+
const metadata = this.endpointMetadata.credentialIssuerMetadata;
|
|
4404
|
+
const types = Array.isArray(credentialTypes) ? credentialTypes : [
|
|
4405
|
+
credentialTypes
|
|
4406
|
+
];
|
|
4407
|
+
if (metadata.credentials_supported && Array.isArray(metadata.credentials_supported)) {
|
|
4408
|
+
let typeSupported = false;
|
|
4409
|
+
metadata.credentials_supported.forEach((supportedCredential) => {
|
|
4410
|
+
const subTypes = (0, import_oid4vci_common25.getTypesFromCredentialSupported)(supportedCredential);
|
|
4411
|
+
if (subTypes.every((t, i) => types[i] === t) || types.length === 1 && (types[0] === supportedCredential.id || subTypes.includes(types[0]))) {
|
|
4412
|
+
typeSupported = true;
|
|
4413
|
+
}
|
|
4414
|
+
});
|
|
4415
|
+
if (!typeSupported) {
|
|
4416
|
+
console.log(`Not all credential types ${JSON.stringify(credentialTypes)} are present in metadata for ${this.getIssuer()}`);
|
|
4417
|
+
}
|
|
4418
|
+
} else if (metadata.credentials_supported && !Array.isArray(metadata.credentials_supported)) {
|
|
4419
|
+
const credentialsSupported = metadata.credentials_supported;
|
|
4420
|
+
if (types.some((type) => !metadata.credentials_supported || !credentialsSupported[type])) {
|
|
4421
|
+
throw Error(`Not all credential types ${JSON.stringify(credentialTypes)} are supported by issuer ${this.getIssuer()}`);
|
|
4422
|
+
}
|
|
4423
|
+
}
|
|
4424
|
+
}
|
|
4425
|
+
const credentialRequestClient = requestBuilder.build();
|
|
4426
|
+
const proofBuilder = ProofOfPossessionBuilder.fromAccessTokenResponse({
|
|
4427
|
+
accessTokenResponse: this.accessTokenResponse,
|
|
4428
|
+
callbacks: proofCallbacks,
|
|
4429
|
+
version: this.version()
|
|
4430
|
+
}).withIssuer(this.getIssuer()).withAlg(this.alg);
|
|
4431
|
+
if (this._state.jwk) {
|
|
4432
|
+
proofBuilder.withJWK(this._state.jwk);
|
|
4433
|
+
}
|
|
4434
|
+
if (this._state.kid) {
|
|
4435
|
+
proofBuilder.withKid(this._state.kid);
|
|
4436
|
+
}
|
|
4437
|
+
if (this.clientId) {
|
|
4438
|
+
proofBuilder.withClientId(this.clientId);
|
|
4439
|
+
}
|
|
4440
|
+
if (jti) {
|
|
4441
|
+
proofBuilder.withJti(jti);
|
|
4442
|
+
}
|
|
4443
|
+
const response = await credentialRequestClient.acquireCredentialsUsingProof({
|
|
4444
|
+
proofInput: proofBuilder,
|
|
4445
|
+
credentialTypes,
|
|
4446
|
+
context,
|
|
4447
|
+
format,
|
|
4448
|
+
createDPoPOpts
|
|
4449
|
+
});
|
|
4450
|
+
this._state.dpopResponseParams = response.params;
|
|
4451
|
+
if (response.errorBody) {
|
|
4452
|
+
debug15(`Credential request error:\r
|
|
4453
|
+
${JSON.stringify(response.errorBody)}`);
|
|
4454
|
+
throw Error(`Retrieving a credential from ${this._state.endpointMetadata?.credential_endpoint} for issuer ${this.getIssuer()} failed with status: ${response.origResponse.status}`);
|
|
4455
|
+
} else if (!response.successBody) {
|
|
4456
|
+
debug15(`Credential request error. No success body`);
|
|
4457
|
+
throw Error(`Retrieving a credential from ${this._state.endpointMetadata?.credential_endpoint} for issuer ${this.getIssuer()} failed as there was no success response body`);
|
|
4458
|
+
}
|
|
4459
|
+
return {
|
|
4460
|
+
...response.successBody,
|
|
4461
|
+
...this.dpopResponseParams && {
|
|
4462
|
+
params: this.dpopResponseParams
|
|
4463
|
+
}
|
|
4464
|
+
};
|
|
4465
|
+
}
|
|
4466
|
+
async exportState() {
|
|
4467
|
+
return JSON.stringify(this._state);
|
|
4468
|
+
}
|
|
4469
|
+
// FIXME: We really should convert <v11 to v12 objects first. Right now the logic doesn't map nicely and is brittle.
|
|
4470
|
+
// We should resolve IDs to objects first in case of strings.
|
|
4471
|
+
// When < v11 convert into a v12 object. When v12 object retain it.
|
|
4472
|
+
// Then match the object array on server metadata
|
|
4473
|
+
getCredentialsSupportedV11(restrictToInitiationTypes, format) {
|
|
4474
|
+
return (0, import_oid4vci_common25.getSupportedCredentials)({
|
|
4475
|
+
issuerMetadata: this.endpointMetadata.credentialIssuerMetadata,
|
|
4476
|
+
version: this.version(),
|
|
4477
|
+
format,
|
|
4478
|
+
types: restrictToInitiationTypes ? this.getCredentialOfferTypes() : void 0
|
|
4479
|
+
});
|
|
4480
|
+
}
|
|
4481
|
+
getCredentialsSupported(format) {
|
|
4482
|
+
return (0, import_oid4vci_common25.getSupportedCredentials)({
|
|
4483
|
+
issuerMetadata: this.endpointMetadata.credentialIssuerMetadata,
|
|
4484
|
+
version: this.version(),
|
|
4485
|
+
format,
|
|
4486
|
+
types: void 0
|
|
4487
|
+
});
|
|
4488
|
+
}
|
|
4489
|
+
getCredentialOfferTypes() {
|
|
4490
|
+
if (!this.credentialOffer) {
|
|
4491
|
+
return [];
|
|
4492
|
+
} else if (this.credentialOffer.version < import_oid4vci_common25.OpenId4VCIVersion.VER_1_0_11) {
|
|
4493
|
+
const orig = this.credentialOffer.original_credential_offer;
|
|
4494
|
+
const types = typeof orig.credential_type === "string" ? [
|
|
4495
|
+
orig.credential_type
|
|
4496
|
+
] : orig.credential_type;
|
|
4497
|
+
const result = [];
|
|
4498
|
+
result[0] = types;
|
|
4499
|
+
return result;
|
|
4500
|
+
} else if (this.credentialOffer.version < import_oid4vci_common25.OpenId4VCIVersion.VER_1_0_13) {
|
|
4501
|
+
return this.credentialOffer.credential_offer.credentials.map((c) => (0, import_oid4vci_common25.getTypesFromObject)(c) ?? []);
|
|
4502
|
+
}
|
|
4503
|
+
throw Error(`This class only supports version 11 and lower! Version: ${this.version()}`);
|
|
4504
|
+
}
|
|
4505
|
+
issuerSupportedFlowTypes() {
|
|
4506
|
+
return this.credentialOffer?.supportedFlows ?? (this._state.endpointMetadata?.credentialIssuerMetadata?.authorization_endpoint ? [
|
|
4507
|
+
import_oid4vci_common25.AuthzFlowType.AUTHORIZATION_CODE_FLOW
|
|
4508
|
+
] : []);
|
|
4509
|
+
}
|
|
4510
|
+
isFlowTypeSupported(flowType) {
|
|
4511
|
+
return this.issuerSupportedFlowTypes().includes(flowType);
|
|
4512
|
+
}
|
|
4513
|
+
get authorizationURL() {
|
|
4514
|
+
return this._state.authorizationURL;
|
|
4515
|
+
}
|
|
4516
|
+
hasAuthorizationURL() {
|
|
4517
|
+
return !!this.authorizationURL;
|
|
4518
|
+
}
|
|
4519
|
+
get credentialOffer() {
|
|
4520
|
+
return this._state.credentialOffer;
|
|
4521
|
+
}
|
|
4522
|
+
version() {
|
|
4523
|
+
return this.credentialOffer?.version ?? import_oid4vci_common25.OpenId4VCIVersion.VER_1_0_11;
|
|
4524
|
+
}
|
|
4525
|
+
get endpointMetadata() {
|
|
4526
|
+
this.assertServerMetadata();
|
|
4527
|
+
return this._state.endpointMetadata;
|
|
4528
|
+
}
|
|
4529
|
+
get kid() {
|
|
4530
|
+
this.assertIssuerData();
|
|
4531
|
+
if (!this._state.kid) {
|
|
4532
|
+
throw new Error("No value for kid is supplied");
|
|
4533
|
+
}
|
|
4534
|
+
return this._state.kid;
|
|
4535
|
+
}
|
|
4536
|
+
get alg() {
|
|
4537
|
+
this.assertIssuerData();
|
|
4538
|
+
if (!this._state.alg) {
|
|
4539
|
+
throw new Error("No value for alg is supplied");
|
|
4540
|
+
}
|
|
4541
|
+
return this._state.alg;
|
|
4542
|
+
}
|
|
4543
|
+
set clientId(value) {
|
|
4544
|
+
this._state.clientId = value;
|
|
4545
|
+
}
|
|
4546
|
+
get clientId() {
|
|
4547
|
+
return this._state.clientId;
|
|
4548
|
+
}
|
|
4549
|
+
hasAccessTokenResponse() {
|
|
4550
|
+
return !!this._state.accessTokenResponse;
|
|
4551
|
+
}
|
|
4552
|
+
get accessTokenResponse() {
|
|
4553
|
+
this.assertAccessToken();
|
|
4554
|
+
return this._state.accessTokenResponse;
|
|
4555
|
+
}
|
|
4556
|
+
get dpopResponseParams() {
|
|
4557
|
+
return this._state.dpopResponseParams;
|
|
4558
|
+
}
|
|
4559
|
+
getIssuer() {
|
|
4560
|
+
this.assertIssuerData();
|
|
4561
|
+
return this._state.credentialIssuer;
|
|
4562
|
+
}
|
|
4563
|
+
getAccessTokenEndpoint() {
|
|
4564
|
+
this.assertIssuerData();
|
|
4565
|
+
return this.endpointMetadata ? this.endpointMetadata.token_endpoint : AccessTokenClientV1_0_11.determineTokenURL({
|
|
4566
|
+
issuerOpts: {
|
|
4567
|
+
issuer: this.getIssuer()
|
|
4568
|
+
}
|
|
4569
|
+
});
|
|
4570
|
+
}
|
|
4571
|
+
getCredentialEndpoint() {
|
|
4572
|
+
this.assertIssuerData();
|
|
4573
|
+
return this.endpointMetadata ? this.endpointMetadata.credential_endpoint : `${this.getIssuer()}/credential`;
|
|
4574
|
+
}
|
|
4575
|
+
hasDeferredCredentialEndpoint() {
|
|
4576
|
+
return !!this.getAccessTokenEndpoint();
|
|
4577
|
+
}
|
|
4578
|
+
getDeferredCredentialEndpoint() {
|
|
4579
|
+
this.assertIssuerData();
|
|
4580
|
+
return this.endpointMetadata ? this.endpointMetadata.credential_endpoint : `${this.getIssuer()}/credential`;
|
|
4581
|
+
}
|
|
4582
|
+
/**
|
|
4583
|
+
* Too bad we need a method like this, but EBSI is not exposing metadata
|
|
4584
|
+
*/
|
|
4585
|
+
isEBSI() {
|
|
4586
|
+
if (this.credentialOffer && this.credentialOffer?.credential_offer?.credentials?.find((cred) => (
|
|
4587
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
4588
|
+
// @ts-ignore
|
|
4589
|
+
typeof cred !== "string" && "trust_framework" in cred && "name" in cred.trust_framework && cred.trust_framework.name.includes("ebsi")
|
|
4590
|
+
))) {
|
|
4591
|
+
return true;
|
|
4592
|
+
}
|
|
4593
|
+
return this.clientId?.includes("ebsi") || this._state.kid?.includes("did:ebsi:") || this.getIssuer().includes("ebsi") || this.endpointMetadata.credentialIssuerMetadata?.authorization_endpoint?.includes("ebsi.eu") || this.endpointMetadata.credentialIssuerMetadata?.authorization_server?.includes("ebsi.eu");
|
|
4594
|
+
}
|
|
4595
|
+
assertIssuerData() {
|
|
4596
|
+
if (!this._state.credentialIssuer) {
|
|
4597
|
+
throw Error(`No credential issuer value present`);
|
|
4598
|
+
} else if (!this._state.credentialOffer && this._state.endpointMetadata && this.issuerSupportedFlowTypes().length === 0) {
|
|
4599
|
+
throw Error(`No issuance initiation or credential offer present`);
|
|
4600
|
+
}
|
|
4601
|
+
}
|
|
4602
|
+
assertServerMetadata() {
|
|
4603
|
+
if (!this._state.endpointMetadata) {
|
|
4604
|
+
throw Error("No server metadata");
|
|
4605
|
+
}
|
|
4606
|
+
}
|
|
4607
|
+
assertAccessToken() {
|
|
4608
|
+
if (!this._state.accessTokenResponse) {
|
|
4609
|
+
throw Error(`No access token present`);
|
|
4610
|
+
}
|
|
4611
|
+
}
|
|
4612
|
+
syncAuthorizationRequestOpts(opts) {
|
|
4613
|
+
let authorizationRequestOpts = {
|
|
4614
|
+
...this._state?.authorizationRequestOpts,
|
|
4615
|
+
...opts
|
|
4616
|
+
};
|
|
4617
|
+
if (!authorizationRequestOpts) {
|
|
4618
|
+
authorizationRequestOpts = {
|
|
4619
|
+
redirectUri: `${import_oid4vci_common25.DefaultURISchemes.CREDENTIAL_OFFER}://`
|
|
4620
|
+
};
|
|
4621
|
+
}
|
|
4622
|
+
const clientId = authorizationRequestOpts.clientId ?? this._state.clientId;
|
|
4623
|
+
this._state.clientId = clientId;
|
|
4624
|
+
authorizationRequestOpts.clientId = clientId;
|
|
4625
|
+
return authorizationRequestOpts;
|
|
4626
|
+
}
|
|
4627
|
+
getAuthorizationCode = /* @__PURE__ */ __name((authorizationResponse, code) => {
|
|
4628
|
+
if (authorizationResponse) {
|
|
4629
|
+
this._state.authorizationCodeResponse = {
|
|
4630
|
+
...(0, import_oid4vci_common25.toAuthorizationResponsePayload)(authorizationResponse)
|
|
4631
|
+
};
|
|
4632
|
+
} else if (code) {
|
|
4633
|
+
this._state.authorizationCodeResponse = {
|
|
4634
|
+
code
|
|
4635
|
+
};
|
|
4636
|
+
}
|
|
4637
|
+
return this._state.authorizationCodeResponse?.code ?? this._state.authorizationCodeResponse?.authorization_code;
|
|
4638
|
+
}, "getAuthorizationCode");
|
|
4639
|
+
};
|
|
4640
|
+
|
|
4641
|
+
// lib/index.ts
|
|
4642
|
+
var LOG2 = import_oid4vci_common26.VCI_LOGGERS.get("sphereon:oid4vci:client");
|
|
4643
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
4644
|
+
0 && (module.exports = {
|
|
4645
|
+
AccessTokenClient,
|
|
4646
|
+
AccessTokenClientV1_0_11,
|
|
4647
|
+
CredentialOfferClient,
|
|
4648
|
+
CredentialOfferClientV1_0_11,
|
|
4649
|
+
CredentialOfferClientV1_0_13,
|
|
4650
|
+
CredentialRequestClient,
|
|
4651
|
+
CredentialRequestClientBuilder,
|
|
4652
|
+
CredentialRequestClientBuilderV1_0_11,
|
|
4653
|
+
CredentialRequestClientBuilderV1_0_13,
|
|
4654
|
+
CredentialRequestClientV1_0_11,
|
|
4655
|
+
LOG,
|
|
4656
|
+
MetadataClient,
|
|
4657
|
+
MetadataClientV1_0_11,
|
|
4658
|
+
MetadataClientV1_0_13,
|
|
4659
|
+
OpenID4VCIClient,
|
|
4660
|
+
OpenID4VCIClientV1_0_11,
|
|
4661
|
+
OpenID4VCIClientV1_0_13,
|
|
4662
|
+
ProofOfPossessionBuilder,
|
|
4663
|
+
acquireAuthorizationChallengeAuthCode,
|
|
4664
|
+
acquireAuthorizationChallengeAuthCodeUsingRequest,
|
|
4665
|
+
buildProof,
|
|
4666
|
+
constructBaseResponse,
|
|
4667
|
+
createAuthorizationChallengeRequest,
|
|
4668
|
+
createAuthorizationRequestUrl,
|
|
4669
|
+
createAuthorizationRequestUrlV1_0_11,
|
|
4670
|
+
createJwtBearerClientAssertion,
|
|
4671
|
+
createSignedAuthRequestWhenNeeded,
|
|
4672
|
+
generateMissingPKCEOpts,
|
|
4673
|
+
handleCredentialOfferUri,
|
|
4674
|
+
isUriEncoded,
|
|
4675
|
+
retrieveWellknown,
|
|
4676
|
+
sendAuthorizationChallengeRequest,
|
|
4677
|
+
sendNotification
|
|
4678
|
+
});
|
|
4679
|
+
//# sourceMappingURL=index.cjs.map
|