@openid4vc/openid4vci 0.3.0-alpha-20250224151429
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/README.md +9 -0
- package/dist/index.d.mts +18898 -0
- package/dist/index.d.ts +18898 -0
- package/dist/index.js +2130 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +2124 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +36 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,2130 @@
|
|
|
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 __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/index.ts
|
|
31
|
+
var src_exports = {};
|
|
32
|
+
__export(src_exports, {
|
|
33
|
+
AuthorizationFlow: () => AuthorizationFlow,
|
|
34
|
+
Openid4vciClient: () => Openid4vciClient,
|
|
35
|
+
Openid4vciDraftVersion: () => Openid4vciDraftVersion,
|
|
36
|
+
Openid4vciError: () => Openid4vciError,
|
|
37
|
+
Openid4vciIssuer: () => Openid4vciIssuer,
|
|
38
|
+
Openid4vciRetrieveCredentialsError: () => Openid4vciRetrieveCredentialsError,
|
|
39
|
+
Openid4vciSendNotificationError: () => Openid4vciSendNotificationError,
|
|
40
|
+
credentialsSupportedToCredentialConfigurationsSupported: () => credentialsSupportedToCredentialConfigurationsSupported,
|
|
41
|
+
extractScopesForCredentialConfigurationIds: () => extractScopesForCredentialConfigurationIds,
|
|
42
|
+
getCredentialConfigurationsMatchingRequestFormat: () => getCredentialConfigurationsMatchingRequestFormat,
|
|
43
|
+
getGlobalConfig: () => import_utils19.getGlobalConfig,
|
|
44
|
+
setGlobalConfig: () => import_utils19.setGlobalConfig
|
|
45
|
+
});
|
|
46
|
+
module.exports = __toCommonJS(src_exports);
|
|
47
|
+
var import_utils19 = require("@openid4vc/utils");
|
|
48
|
+
|
|
49
|
+
// src/credential-request/credential-request-configurations.ts
|
|
50
|
+
var import_utils4 = require("@openid4vc/utils");
|
|
51
|
+
|
|
52
|
+
// src/metadata/credential-issuer/credential-issuer-metadata.ts
|
|
53
|
+
var import_oauth23 = require("@openid4vc/oauth2");
|
|
54
|
+
var import_utils3 = require("@openid4vc/utils");
|
|
55
|
+
|
|
56
|
+
// src/metadata/credential-issuer/z-credential-issuer-metadata.ts
|
|
57
|
+
var import_oauth22 = require("@openid4vc/oauth2");
|
|
58
|
+
var import_utils2 = require("@openid4vc/utils");
|
|
59
|
+
var import_zod9 = __toESM(require("zod"));
|
|
60
|
+
|
|
61
|
+
// src/formats/credential/mso-mdoc/z-mso-mdoc.ts
|
|
62
|
+
var import_zod3 = __toESM(require("zod"));
|
|
63
|
+
|
|
64
|
+
// src/metadata/credential-issuer/z-credential-configuration-supported-common.ts
|
|
65
|
+
var import_zod2 = __toESM(require("zod"));
|
|
66
|
+
|
|
67
|
+
// src/key-attestation/z-key-attestation.ts
|
|
68
|
+
var import_oauth2 = require("@openid4vc/oauth2");
|
|
69
|
+
var import_utils = require("@openid4vc/utils");
|
|
70
|
+
var import_zod = __toESM(require("zod"));
|
|
71
|
+
var zKeyAttestationJwtHeader = import_zod.default.object({
|
|
72
|
+
...import_oauth2.zJwtHeader.shape,
|
|
73
|
+
typ: import_zod.default.literal("keyattestation+jwt")
|
|
74
|
+
}).passthrough().refine(({ kid, jwk }) => jwk === void 0 || kid === void 0, {
|
|
75
|
+
message: `Both 'jwk' and 'kid' are defined. Only one is allowed`
|
|
76
|
+
}).refine(({ trust_chain, kid }) => !trust_chain || !kid, {
|
|
77
|
+
message: `When 'trust_chain' is provided, 'kid' is required`
|
|
78
|
+
});
|
|
79
|
+
var zIso18045 = import_zod.default.enum(["iso_18045_high", "iso_18045_moderate", "iso_18045_enhanced-basic", "iso_18045_basic"]);
|
|
80
|
+
var zIso18045OrStringArray = import_zod.default.array(import_zod.default.union([zIso18045, import_zod.default.string()]));
|
|
81
|
+
var zKeyAttestationJwtPayload = import_zod.default.object({
|
|
82
|
+
...import_oauth2.zJwtPayload.shape,
|
|
83
|
+
iat: import_utils.zInteger,
|
|
84
|
+
attested_keys: import_zod.default.array(import_oauth2.zJwk),
|
|
85
|
+
key_storage: import_zod.default.optional(zIso18045OrStringArray),
|
|
86
|
+
user_authentication: import_zod.default.optional(zIso18045OrStringArray),
|
|
87
|
+
certification: import_zod.default.optional(import_zod.default.string())
|
|
88
|
+
}).passthrough();
|
|
89
|
+
var zKeyAttestationJwtPayloadForUse = (use) => import_zod.default.object({
|
|
90
|
+
...zKeyAttestationJwtPayload.shape,
|
|
91
|
+
// REQUIRED when used as proof_type.attesation directly
|
|
92
|
+
nonce: use === "proof_type.attestation" ? import_zod.default.string({
|
|
93
|
+
message: `Nonce must be defined when key attestation is used as 'proof_type.attestation' directly`
|
|
94
|
+
}) : import_zod.default.optional(import_zod.default.string()),
|
|
95
|
+
// REQUIRED when used within header of proof_type.jwt
|
|
96
|
+
exp: use === "proof_type.jwt" ? import_utils.zInteger : import_zod.default.optional(import_utils.zInteger)
|
|
97
|
+
}).passthrough();
|
|
98
|
+
|
|
99
|
+
// src/metadata/credential-issuer/z-credential-configuration-supported-common.ts
|
|
100
|
+
var zCredentialConfigurationSupportedClaims = import_zod2.default.object({
|
|
101
|
+
mandatory: import_zod2.default.boolean().optional(),
|
|
102
|
+
value_type: import_zod2.default.string().optional(),
|
|
103
|
+
display: import_zod2.default.object({
|
|
104
|
+
name: import_zod2.default.string().optional(),
|
|
105
|
+
locale: import_zod2.default.string().optional()
|
|
106
|
+
}).passthrough().optional()
|
|
107
|
+
}).passthrough();
|
|
108
|
+
var zCredentialConfigurationSupportedCommon = import_zod2.default.object({
|
|
109
|
+
format: import_zod2.default.string(),
|
|
110
|
+
scope: import_zod2.default.string().optional(),
|
|
111
|
+
cryptographic_binding_methods_supported: import_zod2.default.array(import_zod2.default.string()).optional(),
|
|
112
|
+
credential_signing_alg_values_supported: import_zod2.default.array(import_zod2.default.string()).optional(),
|
|
113
|
+
proof_types_supported: import_zod2.default.record(
|
|
114
|
+
import_zod2.default.union([import_zod2.default.literal("jwt"), import_zod2.default.literal("attestation"), import_zod2.default.string()]),
|
|
115
|
+
import_zod2.default.object({
|
|
116
|
+
proof_signing_alg_values_supported: import_zod2.default.array(import_zod2.default.string()),
|
|
117
|
+
key_attestations_required: import_zod2.default.object({
|
|
118
|
+
key_storage: zIso18045OrStringArray.optional(),
|
|
119
|
+
user_authentication: zIso18045OrStringArray.optional()
|
|
120
|
+
}).passthrough().optional()
|
|
121
|
+
})
|
|
122
|
+
).optional(),
|
|
123
|
+
display: import_zod2.default.array(
|
|
124
|
+
import_zod2.default.object({
|
|
125
|
+
name: import_zod2.default.string(),
|
|
126
|
+
locale: import_zod2.default.string().optional(),
|
|
127
|
+
logo: import_zod2.default.object({
|
|
128
|
+
// FIXME: make required again, but need to support draft 11 first
|
|
129
|
+
uri: import_zod2.default.string().optional(),
|
|
130
|
+
alt_text: import_zod2.default.string().optional()
|
|
131
|
+
}).passthrough().optional(),
|
|
132
|
+
description: import_zod2.default.string().optional(),
|
|
133
|
+
background_color: import_zod2.default.string().optional(),
|
|
134
|
+
background_image: import_zod2.default.object({
|
|
135
|
+
// TODO: should be required, but paradym's metadata is wrong here.
|
|
136
|
+
uri: import_zod2.default.string().optional()
|
|
137
|
+
}).passthrough().optional(),
|
|
138
|
+
text_color: import_zod2.default.string().optional()
|
|
139
|
+
}).passthrough()
|
|
140
|
+
).optional()
|
|
141
|
+
}).passthrough();
|
|
142
|
+
|
|
143
|
+
// src/formats/credential/mso-mdoc/z-mso-mdoc.ts
|
|
144
|
+
var zMsoMdocFormatIdentifier = import_zod3.default.literal("mso_mdoc");
|
|
145
|
+
var zMsoMdocCredentialIssuerMetadata = import_zod3.default.object({
|
|
146
|
+
format: zMsoMdocFormatIdentifier,
|
|
147
|
+
doctype: import_zod3.default.string(),
|
|
148
|
+
claims: import_zod3.default.optional(zCredentialConfigurationSupportedClaims),
|
|
149
|
+
order: import_zod3.default.optional(import_zod3.default.array(import_zod3.default.string()))
|
|
150
|
+
});
|
|
151
|
+
var zMsoMdocCredentialRequestFormat = import_zod3.default.object({
|
|
152
|
+
format: zMsoMdocFormatIdentifier,
|
|
153
|
+
doctype: import_zod3.default.string(),
|
|
154
|
+
claims: import_zod3.default.optional(zCredentialConfigurationSupportedClaims)
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
// src/formats/credential/sd-jwt-vc/z-sd-jwt-vc.ts
|
|
158
|
+
var import_zod4 = __toESM(require("zod"));
|
|
159
|
+
var zSdJwtVcFormatIdentifier = import_zod4.default.literal("vc+sd-jwt");
|
|
160
|
+
var zSdJwtVcCredentialIssuerMetadata = import_zod4.default.object({
|
|
161
|
+
vct: import_zod4.default.string(),
|
|
162
|
+
format: zSdJwtVcFormatIdentifier,
|
|
163
|
+
claims: import_zod4.default.optional(zCredentialConfigurationSupportedClaims),
|
|
164
|
+
order: import_zod4.default.optional(import_zod4.default.array(import_zod4.default.string()))
|
|
165
|
+
});
|
|
166
|
+
var zSdJwtVcCredentialRequestFormat = import_zod4.default.object({
|
|
167
|
+
format: zSdJwtVcFormatIdentifier,
|
|
168
|
+
vct: import_zod4.default.string(),
|
|
169
|
+
claims: import_zod4.default.optional(zCredentialConfigurationSupportedClaims)
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
// src/formats/credential/w3c-vc/z-w3c-ldp-vc.ts
|
|
173
|
+
var import_zod6 = __toESM(require("zod"));
|
|
174
|
+
|
|
175
|
+
// src/formats/credential/w3c-vc/z-w3c-vc-common.ts
|
|
176
|
+
var import_zod5 = __toESM(require("zod"));
|
|
177
|
+
var zCredentialSubjectLeafType = import_zod5.default.object({
|
|
178
|
+
mandatory: import_zod5.default.boolean().optional(),
|
|
179
|
+
value_type: import_zod5.default.string().optional(),
|
|
180
|
+
display: import_zod5.default.array(
|
|
181
|
+
import_zod5.default.object({
|
|
182
|
+
name: import_zod5.default.string().optional(),
|
|
183
|
+
locale: import_zod5.default.string().optional()
|
|
184
|
+
}).passthrough()
|
|
185
|
+
).optional()
|
|
186
|
+
}).passthrough();
|
|
187
|
+
var zClaimValueSchema = import_zod5.default.union([import_zod5.default.array(import_zod5.default.any()), import_zod5.default.record(import_zod5.default.string(), import_zod5.default.any()), zCredentialSubjectLeafType]);
|
|
188
|
+
var zW3cVcCredentialSubject = import_zod5.default.record(import_zod5.default.string(), zClaimValueSchema);
|
|
189
|
+
var zW3cVcJsonLdCredentialDefinition = import_zod5.default.object({
|
|
190
|
+
"@context": import_zod5.default.array(import_zod5.default.string()),
|
|
191
|
+
type: import_zod5.default.array(import_zod5.default.string()),
|
|
192
|
+
credentialSubject: zW3cVcCredentialSubject.optional()
|
|
193
|
+
}).passthrough();
|
|
194
|
+
|
|
195
|
+
// src/formats/credential/w3c-vc/z-w3c-ldp-vc.ts
|
|
196
|
+
var zLdpVcFormatIdentifier = import_zod6.default.literal("ldp_vc");
|
|
197
|
+
var zLdpVcCredentialIssuerMetadata = import_zod6.default.object({
|
|
198
|
+
format: zLdpVcFormatIdentifier,
|
|
199
|
+
credential_definition: zW3cVcJsonLdCredentialDefinition,
|
|
200
|
+
order: import_zod6.default.array(import_zod6.default.string()).optional()
|
|
201
|
+
});
|
|
202
|
+
var zLdpVcCredentialIssuerMetadataDraft11 = import_zod6.default.object({
|
|
203
|
+
order: import_zod6.default.array(import_zod6.default.string()).optional(),
|
|
204
|
+
format: zLdpVcFormatIdentifier,
|
|
205
|
+
// Credential definition was spread on top level instead of a separatey property in v11
|
|
206
|
+
// As well as using types instead of type
|
|
207
|
+
"@context": import_zod6.default.array(import_zod6.default.string()),
|
|
208
|
+
types: import_zod6.default.array(import_zod6.default.string()),
|
|
209
|
+
credentialSubject: zW3cVcCredentialSubject.optional()
|
|
210
|
+
}).passthrough();
|
|
211
|
+
var zLdpVcCredentialIssuerMetadataDraft11To14 = zLdpVcCredentialIssuerMetadataDraft11.transform(
|
|
212
|
+
({ "@context": context, types, credentialSubject, ...rest }) => ({
|
|
213
|
+
...rest,
|
|
214
|
+
credential_definition: {
|
|
215
|
+
"@context": context,
|
|
216
|
+
type: types,
|
|
217
|
+
// Prevent weird typing issue with optional vs undefined
|
|
218
|
+
...credentialSubject ? { credentialSubject } : {}
|
|
219
|
+
}
|
|
220
|
+
})
|
|
221
|
+
);
|
|
222
|
+
var zLdpVcCredentialIssuerMetadataDraft14To11 = zLdpVcCredentialIssuerMetadata.passthrough().transform(({ credential_definition: { type, ...credentialDefinition }, ...rest }) => ({
|
|
223
|
+
...rest,
|
|
224
|
+
...credentialDefinition,
|
|
225
|
+
types: type
|
|
226
|
+
})).and(zLdpVcCredentialIssuerMetadataDraft11);
|
|
227
|
+
var zLdpVcCredentialRequestFormat = import_zod6.default.object({
|
|
228
|
+
format: zLdpVcFormatIdentifier,
|
|
229
|
+
credential_definition: zW3cVcJsonLdCredentialDefinition
|
|
230
|
+
});
|
|
231
|
+
var zLdpVcCredentialRequestDraft11 = import_zod6.default.object({
|
|
232
|
+
format: zLdpVcFormatIdentifier,
|
|
233
|
+
credential_definition: import_zod6.default.object({
|
|
234
|
+
"@context": import_zod6.default.array(import_zod6.default.string()),
|
|
235
|
+
// credential_definition was using types instead of type in v11
|
|
236
|
+
types: import_zod6.default.array(import_zod6.default.string()),
|
|
237
|
+
credentialSubject: zW3cVcCredentialSubject.optional()
|
|
238
|
+
})
|
|
239
|
+
}).passthrough();
|
|
240
|
+
var zLdpVcCredentialRequestDraft11To14 = zLdpVcCredentialRequestDraft11.transform(
|
|
241
|
+
({ credential_definition: { types, ...restCredentialDefinition }, ...rest }) => ({
|
|
242
|
+
...rest,
|
|
243
|
+
credential_definition: {
|
|
244
|
+
...restCredentialDefinition,
|
|
245
|
+
type: types
|
|
246
|
+
}
|
|
247
|
+
})
|
|
248
|
+
);
|
|
249
|
+
var zLdpVcCredentialRequestDraft14To11 = zLdpVcCredentialRequestFormat.passthrough().transform(({ credential_definition: { type, ...restCredentialDefinition }, ...rest }) => ({
|
|
250
|
+
...rest,
|
|
251
|
+
credential_definition: {
|
|
252
|
+
...restCredentialDefinition,
|
|
253
|
+
types: type
|
|
254
|
+
}
|
|
255
|
+
})).and(zLdpVcCredentialRequestDraft11);
|
|
256
|
+
|
|
257
|
+
// src/formats/credential/w3c-vc/z-w3c-jwt-vc-json-ld.ts
|
|
258
|
+
var import_zod7 = __toESM(require("zod"));
|
|
259
|
+
var zJwtVcJsonLdFormatIdentifier = import_zod7.default.literal("jwt_vc_json-ld");
|
|
260
|
+
var zJwtVcJsonLdCredentialIssuerMetadata = import_zod7.default.object({
|
|
261
|
+
format: zJwtVcJsonLdFormatIdentifier,
|
|
262
|
+
credential_definition: zW3cVcJsonLdCredentialDefinition,
|
|
263
|
+
order: import_zod7.default.optional(import_zod7.default.array(import_zod7.default.string()))
|
|
264
|
+
});
|
|
265
|
+
var zJwtVcJsonLdCredentialIssuerMetadataDraft11 = import_zod7.default.object({
|
|
266
|
+
order: import_zod7.default.array(import_zod7.default.string()).optional(),
|
|
267
|
+
format: zJwtVcJsonLdFormatIdentifier,
|
|
268
|
+
// Credential definition was spread on top level instead of a separatey property in v11
|
|
269
|
+
// As well as using types instead of type
|
|
270
|
+
"@context": import_zod7.default.array(import_zod7.default.string()),
|
|
271
|
+
types: import_zod7.default.array(import_zod7.default.string()),
|
|
272
|
+
credentialSubject: zW3cVcCredentialSubject.optional()
|
|
273
|
+
}).passthrough();
|
|
274
|
+
var zJwtVcJsonLdCredentialIssuerMetadataDraft11To14 = zJwtVcJsonLdCredentialIssuerMetadataDraft11.transform(
|
|
275
|
+
({ "@context": context, types, credentialSubject, ...rest }) => ({
|
|
276
|
+
...rest,
|
|
277
|
+
credential_definition: {
|
|
278
|
+
"@context": context,
|
|
279
|
+
type: types,
|
|
280
|
+
// Prevent weird typing issue with optional vs undefined
|
|
281
|
+
...credentialSubject ? { credentialSubject } : {}
|
|
282
|
+
}
|
|
283
|
+
})
|
|
284
|
+
);
|
|
285
|
+
var zJwtVcJsonLdCredentialIssuerMetadataDraft14To11 = zJwtVcJsonLdCredentialIssuerMetadata.passthrough().transform(({ credential_definition: { type, ...credentialDefinition }, ...rest }) => ({
|
|
286
|
+
...rest,
|
|
287
|
+
...credentialDefinition,
|
|
288
|
+
types: type
|
|
289
|
+
})).and(zJwtVcJsonLdCredentialIssuerMetadataDraft11);
|
|
290
|
+
var zJwtVcJsonLdCredentialRequestFormat = import_zod7.default.object({
|
|
291
|
+
format: zJwtVcJsonLdFormatIdentifier,
|
|
292
|
+
credential_definition: zW3cVcJsonLdCredentialDefinition
|
|
293
|
+
});
|
|
294
|
+
var zJwtVcJsonLdCredentialRequestDraft11 = import_zod7.default.object({
|
|
295
|
+
format: zJwtVcJsonLdFormatIdentifier,
|
|
296
|
+
credential_definition: import_zod7.default.object({
|
|
297
|
+
"@context": import_zod7.default.array(import_zod7.default.string()),
|
|
298
|
+
// credential_definition was using types instead of type in v11
|
|
299
|
+
types: import_zod7.default.array(import_zod7.default.string()),
|
|
300
|
+
credentialSubject: import_zod7.default.optional(zW3cVcCredentialSubject)
|
|
301
|
+
}).passthrough()
|
|
302
|
+
}).passthrough();
|
|
303
|
+
var zJwtVcJsonLdCredentialRequestDraft11To14 = zJwtVcJsonLdCredentialRequestDraft11.transform(
|
|
304
|
+
({ credential_definition: { types, ...restCredentialDefinition }, ...rest }) => ({
|
|
305
|
+
...rest,
|
|
306
|
+
credential_definition: {
|
|
307
|
+
...restCredentialDefinition,
|
|
308
|
+
type: types
|
|
309
|
+
}
|
|
310
|
+
})
|
|
311
|
+
);
|
|
312
|
+
var zJwtVcJsonLdCredentialRequestDraft14To11 = zJwtVcJsonLdCredentialRequestFormat.passthrough().transform(({ credential_definition: { type, ...restCredentialDefinition }, ...rest }) => ({
|
|
313
|
+
...rest,
|
|
314
|
+
credential_definition: {
|
|
315
|
+
...restCredentialDefinition,
|
|
316
|
+
types: type
|
|
317
|
+
}
|
|
318
|
+
})).and(zJwtVcJsonLdCredentialRequestDraft11);
|
|
319
|
+
|
|
320
|
+
// src/formats/credential/w3c-vc/z-w3c-jwt-vc-json.ts
|
|
321
|
+
var import_zod8 = __toESM(require("zod"));
|
|
322
|
+
var zJwtVcJsonFormatIdentifier = import_zod8.default.literal("jwt_vc_json");
|
|
323
|
+
var zJwtVcJsonCredentialDefinition = import_zod8.default.object({
|
|
324
|
+
type: import_zod8.default.array(import_zod8.default.string()),
|
|
325
|
+
credentialSubject: zW3cVcCredentialSubject.optional()
|
|
326
|
+
}).passthrough();
|
|
327
|
+
var zJwtVcJsonCredentialIssuerMetadata = import_zod8.default.object({
|
|
328
|
+
format: zJwtVcJsonFormatIdentifier,
|
|
329
|
+
credential_definition: zJwtVcJsonCredentialDefinition,
|
|
330
|
+
order: import_zod8.default.array(import_zod8.default.string()).optional()
|
|
331
|
+
});
|
|
332
|
+
var zJwtVcJsonCredentialIssuerMetadataDraft11 = import_zod8.default.object({
|
|
333
|
+
format: zJwtVcJsonFormatIdentifier,
|
|
334
|
+
order: import_zod8.default.array(import_zod8.default.string()).optional(),
|
|
335
|
+
// Credential definition was spread on top level instead of a separatey property in v11
|
|
336
|
+
// As well as using types instead of type
|
|
337
|
+
types: import_zod8.default.array(import_zod8.default.string()),
|
|
338
|
+
credentialSubject: zW3cVcCredentialSubject.optional()
|
|
339
|
+
}).passthrough();
|
|
340
|
+
var zJwtVcJsonCredentialIssuerMetadataDraft11To14 = zJwtVcJsonCredentialIssuerMetadataDraft11.transform(
|
|
341
|
+
({ types, credentialSubject, ...rest }) => ({
|
|
342
|
+
...rest,
|
|
343
|
+
credential_definition: {
|
|
344
|
+
type: types,
|
|
345
|
+
// Prevent weird typing issue with optional vs undefined
|
|
346
|
+
...credentialSubject ? { credentialSubject } : {}
|
|
347
|
+
}
|
|
348
|
+
})
|
|
349
|
+
);
|
|
350
|
+
var zJwtVcJsonCredentialIssuerMetadataDraft14To11 = zJwtVcJsonCredentialIssuerMetadata.passthrough().transform(({ credential_definition: { type, ...credentialDefinition }, ...rest }) => ({
|
|
351
|
+
...rest,
|
|
352
|
+
types: type,
|
|
353
|
+
...credentialDefinition
|
|
354
|
+
})).and(zJwtVcJsonCredentialIssuerMetadataDraft11);
|
|
355
|
+
var zJwtVcJsonCredentialRequestFormat = import_zod8.default.object({
|
|
356
|
+
format: zJwtVcJsonFormatIdentifier,
|
|
357
|
+
credential_definition: zJwtVcJsonCredentialDefinition
|
|
358
|
+
});
|
|
359
|
+
var zJwtVcJsonCredentialRequestDraft11 = import_zod8.default.object({
|
|
360
|
+
format: zJwtVcJsonFormatIdentifier,
|
|
361
|
+
// Credential definition was spread on top level instead of a separatey property in v11
|
|
362
|
+
// As well as using types instead of type
|
|
363
|
+
types: import_zod8.default.array(import_zod8.default.string()),
|
|
364
|
+
credentialSubject: import_zod8.default.optional(zW3cVcCredentialSubject)
|
|
365
|
+
}).passthrough();
|
|
366
|
+
var zJwtVcJsonCredentialRequestDraft11To14 = zJwtVcJsonCredentialRequestDraft11.transform(
|
|
367
|
+
({ types, credentialSubject, ...rest }) => {
|
|
368
|
+
return {
|
|
369
|
+
...rest,
|
|
370
|
+
credential_definition: {
|
|
371
|
+
type: types,
|
|
372
|
+
// Prevent weird typing issue with optional vs undefined
|
|
373
|
+
...credentialSubject ? { credentialSubject } : {}
|
|
374
|
+
}
|
|
375
|
+
};
|
|
376
|
+
}
|
|
377
|
+
);
|
|
378
|
+
var zJwtVcJsonCredentialRequestDraft14To11 = zJwtVcJsonCredentialRequestFormat.passthrough().transform(({ credential_definition: { type, ...credentialDefinition }, ...rest }) => ({
|
|
379
|
+
...rest,
|
|
380
|
+
types: type,
|
|
381
|
+
...credentialDefinition
|
|
382
|
+
})).and(zJwtVcJsonCredentialRequestDraft11);
|
|
383
|
+
|
|
384
|
+
// src/version.ts
|
|
385
|
+
var Openid4vciDraftVersion = /* @__PURE__ */ ((Openid4vciDraftVersion2) => {
|
|
386
|
+
Openid4vciDraftVersion2["Draft14"] = "Draft14";
|
|
387
|
+
Openid4vciDraftVersion2["Draft11"] = "Draft11";
|
|
388
|
+
return Openid4vciDraftVersion2;
|
|
389
|
+
})(Openid4vciDraftVersion || {});
|
|
390
|
+
|
|
391
|
+
// src/metadata/credential-issuer/z-credential-issuer-metadata.ts
|
|
392
|
+
var allCredentialIssuerMetadataFormats = [
|
|
393
|
+
zSdJwtVcCredentialIssuerMetadata,
|
|
394
|
+
zMsoMdocCredentialIssuerMetadata,
|
|
395
|
+
zJwtVcJsonLdCredentialIssuerMetadata,
|
|
396
|
+
zLdpVcCredentialIssuerMetadata,
|
|
397
|
+
zJwtVcJsonCredentialIssuerMetadata
|
|
398
|
+
];
|
|
399
|
+
var allCredentialIssuerMetadataFormatIdentifiers = allCredentialIssuerMetadataFormats.map(
|
|
400
|
+
(format) => format.shape.format.value
|
|
401
|
+
);
|
|
402
|
+
var zCredentialConfigurationSupportedWithFormats = zCredentialConfigurationSupportedCommon.transform(
|
|
403
|
+
(data, ctx) => {
|
|
404
|
+
if (!allCredentialIssuerMetadataFormatIdentifiers.includes(data.format)) return data;
|
|
405
|
+
const result = import_zod9.default.object({}).passthrough().and(import_zod9.default.discriminatedUnion("format", allCredentialIssuerMetadataFormats)).safeParse(data);
|
|
406
|
+
if (result.success) {
|
|
407
|
+
return result.data;
|
|
408
|
+
}
|
|
409
|
+
for (const issue of result.error.issues) {
|
|
410
|
+
ctx.addIssue(issue);
|
|
411
|
+
}
|
|
412
|
+
return import_zod9.default.NEVER;
|
|
413
|
+
}
|
|
414
|
+
);
|
|
415
|
+
var zCredentialIssuerMetadataDisplayEntry = import_zod9.default.object({
|
|
416
|
+
name: import_zod9.default.string().optional(),
|
|
417
|
+
locale: import_zod9.default.string().optional(),
|
|
418
|
+
logo: import_zod9.default.object({
|
|
419
|
+
// FIXME: make required again, but need to support draft 11 first
|
|
420
|
+
uri: import_zod9.default.string().optional(),
|
|
421
|
+
alt_text: import_zod9.default.string().optional()
|
|
422
|
+
}).passthrough().optional()
|
|
423
|
+
}).passthrough();
|
|
424
|
+
var zCredentialIssuerMetadataDraft14 = import_zod9.default.object({
|
|
425
|
+
credential_issuer: import_utils2.zHttpsUrl,
|
|
426
|
+
authorization_servers: import_zod9.default.array(import_utils2.zHttpsUrl).optional(),
|
|
427
|
+
credential_endpoint: import_utils2.zHttpsUrl,
|
|
428
|
+
deferred_credential_endpoint: import_utils2.zHttpsUrl.optional(),
|
|
429
|
+
notification_endpoint: import_utils2.zHttpsUrl.optional(),
|
|
430
|
+
// Added after draft 14, but needed for proper
|
|
431
|
+
nonce_endpoint: import_utils2.zHttpsUrl.optional(),
|
|
432
|
+
credential_response_encryption: import_zod9.default.object({
|
|
433
|
+
alg_values_supported: import_zod9.default.array(import_zod9.default.string()),
|
|
434
|
+
enc_values_supported: import_zod9.default.array(import_zod9.default.string()),
|
|
435
|
+
encryption_required: import_zod9.default.boolean()
|
|
436
|
+
}).passthrough().optional(),
|
|
437
|
+
batch_credential_issuance: import_zod9.default.object({
|
|
438
|
+
batch_size: import_zod9.default.number().positive()
|
|
439
|
+
}).passthrough().optional(),
|
|
440
|
+
signed_metadata: import_oauth22.zCompactJwt.optional(),
|
|
441
|
+
display: import_zod9.default.array(zCredentialIssuerMetadataDisplayEntry).optional(),
|
|
442
|
+
credential_configurations_supported: import_zod9.default.record(import_zod9.default.string(), zCredentialConfigurationSupportedWithFormats)
|
|
443
|
+
}).passthrough();
|
|
444
|
+
var zCredentialConfigurationSupportedDraft11To14 = import_zod9.default.object({
|
|
445
|
+
id: import_zod9.default.string().optional(),
|
|
446
|
+
format: import_zod9.default.string(),
|
|
447
|
+
cryptographic_suites_supported: import_zod9.default.array(import_zod9.default.string()).optional(),
|
|
448
|
+
display: import_zod9.default.array(
|
|
449
|
+
import_zod9.default.object({
|
|
450
|
+
logo: import_zod9.default.object({
|
|
451
|
+
url: import_zod9.default.string().url().optional()
|
|
452
|
+
}).passthrough().optional(),
|
|
453
|
+
background_image: import_zod9.default.object({
|
|
454
|
+
url: import_zod9.default.string().url().optional()
|
|
455
|
+
}).passthrough().optional()
|
|
456
|
+
}).passthrough()
|
|
457
|
+
).optional()
|
|
458
|
+
}).passthrough().transform(({ cryptographic_suites_supported, display, id, ...rest }) => ({
|
|
459
|
+
...rest,
|
|
460
|
+
...cryptographic_suites_supported ? { credential_signing_alg_values_supported: cryptographic_suites_supported } : {},
|
|
461
|
+
...display ? {
|
|
462
|
+
display: display.map(({ logo, background_image, ...displayRest }) => ({
|
|
463
|
+
...displayRest,
|
|
464
|
+
// url became uri and also required
|
|
465
|
+
// so if there's no url in the logo, we remove the whole logo object
|
|
466
|
+
...logo?.url ? {
|
|
467
|
+
// TODO: we should add the other params from logo as well
|
|
468
|
+
logo: {
|
|
469
|
+
uri: logo.url
|
|
470
|
+
}
|
|
471
|
+
} : {},
|
|
472
|
+
// TODO: we should add the other params from background_image as well
|
|
473
|
+
// url became uri and also required
|
|
474
|
+
// so if there's no url in the background_image, we remove the whole logo object
|
|
475
|
+
...background_image?.url ? {
|
|
476
|
+
background_image: {
|
|
477
|
+
uri: background_image.url
|
|
478
|
+
}
|
|
479
|
+
} : {}
|
|
480
|
+
}))
|
|
481
|
+
} : {}
|
|
482
|
+
})).transform((data, ctx) => {
|
|
483
|
+
const formatSpecificTransformations = {
|
|
484
|
+
[zLdpVcFormatIdentifier.value]: zLdpVcCredentialIssuerMetadataDraft11To14,
|
|
485
|
+
[zJwtVcJsonFormatIdentifier.value]: zJwtVcJsonCredentialIssuerMetadataDraft11To14,
|
|
486
|
+
[zJwtVcJsonLdFormatIdentifier.value]: zJwtVcJsonLdCredentialIssuerMetadataDraft11To14
|
|
487
|
+
};
|
|
488
|
+
if (!Object.keys(formatSpecificTransformations).includes(data.format)) return data;
|
|
489
|
+
const schema = formatSpecificTransformations[data.format];
|
|
490
|
+
const result = schema.safeParse(data);
|
|
491
|
+
if (result.success) return result.data;
|
|
492
|
+
for (const issue of result.error.issues) {
|
|
493
|
+
ctx.addIssue(issue);
|
|
494
|
+
}
|
|
495
|
+
return import_zod9.default.NEVER;
|
|
496
|
+
}).pipe(zCredentialConfigurationSupportedWithFormats);
|
|
497
|
+
var zCredentialConfigurationSupportedDraft14To11 = zCredentialConfigurationSupportedWithFormats.and(
|
|
498
|
+
import_zod9.default.object({
|
|
499
|
+
id: import_zod9.default.string()
|
|
500
|
+
}).passthrough()
|
|
501
|
+
).transform(({ id, credential_signing_alg_values_supported, display, proof_types_supported, scope, ...rest }) => ({
|
|
502
|
+
...rest,
|
|
503
|
+
...credential_signing_alg_values_supported ? { cryptographic_suites_supported: credential_signing_alg_values_supported } : {},
|
|
504
|
+
...display ? {
|
|
505
|
+
display: display.map(({ logo, background_image, ...displayRest }) => {
|
|
506
|
+
const { uri: logoUri, ...logoRest } = logo ?? {};
|
|
507
|
+
const { uri: backgroundImageUri, ...backgroundImageRest } = background_image ?? {};
|
|
508
|
+
return {
|
|
509
|
+
...displayRest,
|
|
510
|
+
// draft 11 uses url, draft 13/14 uses uri
|
|
511
|
+
...logoUri ? { logo: { url: logoUri, ...logoRest } } : {},
|
|
512
|
+
// draft 11 uses url, draft 13/14 uses uri
|
|
513
|
+
...backgroundImageUri ? { logo: { url: backgroundImageUri, ...backgroundImageRest } } : {}
|
|
514
|
+
};
|
|
515
|
+
})
|
|
516
|
+
} : {},
|
|
517
|
+
id
|
|
518
|
+
})).pipe(
|
|
519
|
+
import_zod9.default.union([
|
|
520
|
+
zLdpVcCredentialIssuerMetadataDraft14To11,
|
|
521
|
+
zJwtVcJsonCredentialIssuerMetadataDraft14To11,
|
|
522
|
+
zJwtVcJsonLdCredentialIssuerMetadataDraft14To11,
|
|
523
|
+
// To handle unrecognized formats and not error immediately we allow the common format as well
|
|
524
|
+
// but they can't use any of the foramt identifiers that have a specific transformation. This way if a format is
|
|
525
|
+
// has a transformation it NEEDS to use the format specific transformation, and otherwise we fall back to the common validation
|
|
526
|
+
import_zod9.default.object({
|
|
527
|
+
format: import_zod9.default.string().refine(
|
|
528
|
+
(input) => ![
|
|
529
|
+
zLdpVcFormatIdentifier.value,
|
|
530
|
+
zJwtVcJsonFormatIdentifier.value,
|
|
531
|
+
zJwtVcJsonLdFormatIdentifier.value
|
|
532
|
+
].includes(input)
|
|
533
|
+
)
|
|
534
|
+
}).passthrough()
|
|
535
|
+
])
|
|
536
|
+
);
|
|
537
|
+
var zCredentialIssuerMetadataDraft11To14 = import_zod9.default.object({
|
|
538
|
+
authorization_server: import_zod9.default.string().optional(),
|
|
539
|
+
credentials_supported: import_zod9.default.array(
|
|
540
|
+
import_zod9.default.object({
|
|
541
|
+
id: import_zod9.default.string().optional()
|
|
542
|
+
}).passthrough()
|
|
543
|
+
)
|
|
544
|
+
}).passthrough().transform(({ authorization_server, credentials_supported, ...rest }) => {
|
|
545
|
+
return {
|
|
546
|
+
...rest,
|
|
547
|
+
...authorization_server ? { authorization_servers: [authorization_server] } : {},
|
|
548
|
+
// Go from array to map but keep v11 structure
|
|
549
|
+
credential_configurations_supported: Object.fromEntries(
|
|
550
|
+
credentials_supported.map((supported) => supported.id ? [supported.id, supported] : void 0).filter((i) => i !== void 0)
|
|
551
|
+
)
|
|
552
|
+
};
|
|
553
|
+
}).pipe(
|
|
554
|
+
import_zod9.default.object({
|
|
555
|
+
// Update from v11 structrue to v14 structure
|
|
556
|
+
credential_configurations_supported: import_zod9.default.record(import_zod9.default.string(), zCredentialConfigurationSupportedDraft11To14)
|
|
557
|
+
}).passthrough()
|
|
558
|
+
).pipe(zCredentialIssuerMetadataDraft14);
|
|
559
|
+
var zCredentialIssuerMetadataWithDraft11 = zCredentialIssuerMetadataDraft14.transform((issuerMetadata) => ({
|
|
560
|
+
...issuerMetadata,
|
|
561
|
+
...issuerMetadata.authorization_servers ? { authorization_server: issuerMetadata.authorization_servers[0] } : {},
|
|
562
|
+
credentials_supported: Object.entries(issuerMetadata.credential_configurations_supported).map(([id, value]) => ({
|
|
563
|
+
...value,
|
|
564
|
+
id
|
|
565
|
+
}))
|
|
566
|
+
})).pipe(
|
|
567
|
+
zCredentialIssuerMetadataDraft14.extend({
|
|
568
|
+
credentials_supported: import_zod9.default.array(zCredentialConfigurationSupportedDraft14To11)
|
|
569
|
+
})
|
|
570
|
+
);
|
|
571
|
+
var zCredentialIssuerMetadata = import_zod9.default.union([
|
|
572
|
+
// First prioritize draft 14 (and 13)
|
|
573
|
+
zCredentialIssuerMetadataDraft14,
|
|
574
|
+
// Then try parsing draft 11 and transform into draft 14
|
|
575
|
+
zCredentialIssuerMetadataDraft11To14
|
|
576
|
+
]);
|
|
577
|
+
var zCredentialIssuerMetadataWithDraftVersion = import_zod9.default.union([
|
|
578
|
+
// First prioritize draft 14 (and 13)
|
|
579
|
+
zCredentialIssuerMetadataDraft14.transform((credentialIssuerMetadata) => ({
|
|
580
|
+
credentialIssuerMetadata,
|
|
581
|
+
originalDraftVersion: "Draft14" /* Draft14 */
|
|
582
|
+
})),
|
|
583
|
+
// Then try parsing draft 11 and transform into draft 14
|
|
584
|
+
zCredentialIssuerMetadataDraft11To14.transform((credentialIssuerMetadata) => ({
|
|
585
|
+
credentialIssuerMetadata,
|
|
586
|
+
originalDraftVersion: "Draft11" /* Draft11 */
|
|
587
|
+
}))
|
|
588
|
+
]);
|
|
589
|
+
|
|
590
|
+
// src/metadata/credential-issuer/credential-issuer-metadata.ts
|
|
591
|
+
var wellKnownCredentialIssuerSuffix = ".well-known/openid-credential-issuer";
|
|
592
|
+
async function fetchCredentialIssuerMetadata(credentialIssuer, fetch) {
|
|
593
|
+
const wellKnownMetadataUrl = (0, import_utils3.joinUriParts)(credentialIssuer, [wellKnownCredentialIssuerSuffix]);
|
|
594
|
+
const result = await (0, import_oauth23.fetchWellKnownMetadata)(wellKnownMetadataUrl, zCredentialIssuerMetadataWithDraftVersion, fetch);
|
|
595
|
+
if (result && result.credentialIssuerMetadata.credential_issuer !== credentialIssuer) {
|
|
596
|
+
throw new import_oauth23.Oauth2Error(
|
|
597
|
+
`The 'credential_issuer' parameter '${result.credentialIssuerMetadata.credential_issuer}' in the well known credential issuer metadata at '${wellKnownMetadataUrl}' does not match the provided credential issuer '${credentialIssuer}'.`
|
|
598
|
+
);
|
|
599
|
+
}
|
|
600
|
+
return result;
|
|
601
|
+
}
|
|
602
|
+
function extractKnownCredentialConfigurationSupportedFormats(credentialConfigurationsSupported) {
|
|
603
|
+
return Object.fromEntries(
|
|
604
|
+
Object.entries(credentialConfigurationsSupported).filter(
|
|
605
|
+
(entry) => allCredentialIssuerMetadataFormatIdentifiers.includes(entry[1].format)
|
|
606
|
+
)
|
|
607
|
+
);
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
// src/credential-request/credential-request-configurations.ts
|
|
611
|
+
function getCredentialConfigurationsMatchingRequestFormat({
|
|
612
|
+
requestFormat,
|
|
613
|
+
credentialConfigurations
|
|
614
|
+
}) {
|
|
615
|
+
const knownCredentialConfigurations = extractKnownCredentialConfigurationSupportedFormats(credentialConfigurations);
|
|
616
|
+
return Object.fromEntries(
|
|
617
|
+
Object.entries(knownCredentialConfigurations).filter(([, credentialConfiguration]) => {
|
|
618
|
+
if (credentialConfiguration.format !== requestFormat.format) return false;
|
|
619
|
+
const r = requestFormat;
|
|
620
|
+
const c = credentialConfiguration;
|
|
621
|
+
if ((c.format === "ldp_vc" || c.format === "jwt_vc_json-ld") && r.format === c.format) {
|
|
622
|
+
return (0, import_utils4.arrayEqualsIgnoreOrder)(r.credential_definition.type, c.credential_definition.type) && (0, import_utils4.arrayEqualsIgnoreOrder)(r.credential_definition["@context"], c.credential_definition["@context"]);
|
|
623
|
+
}
|
|
624
|
+
if (c.format === "jwt_vc_json" && r.format === c.format) {
|
|
625
|
+
return (0, import_utils4.arrayEqualsIgnoreOrder)(r.credential_definition.type, c.credential_definition.type);
|
|
626
|
+
}
|
|
627
|
+
if (c.format === "vc+sd-jwt" && r.format === c.format) {
|
|
628
|
+
return r.vct === c.vct;
|
|
629
|
+
}
|
|
630
|
+
if (c.format === "mso_mdoc" && r.format === c.format) {
|
|
631
|
+
return r.doctype === c.doctype;
|
|
632
|
+
}
|
|
633
|
+
return false;
|
|
634
|
+
})
|
|
635
|
+
);
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
// src/error/Openid4vciError.ts
|
|
639
|
+
var Openid4vciError = class extends Error {
|
|
640
|
+
constructor(message, options) {
|
|
641
|
+
const errorMessage = message ?? "Unknown error occured.";
|
|
642
|
+
const causeMessage = options?.cause instanceof Error ? ` ${options.cause.message}` : options?.cause ? ` ${options?.cause}` : "";
|
|
643
|
+
super(`${errorMessage}${causeMessage}`);
|
|
644
|
+
this.cause = options?.cause;
|
|
645
|
+
}
|
|
646
|
+
};
|
|
647
|
+
|
|
648
|
+
// src/error/Openid4vciRetrieveCredentialsError.ts
|
|
649
|
+
var Openid4vciRetrieveCredentialsError = class extends Openid4vciError {
|
|
650
|
+
constructor(message, response, responseText) {
|
|
651
|
+
super(
|
|
652
|
+
`${message}
|
|
653
|
+
${JSON.stringify(response.credentialResponseResult?.data ?? response.credentialErrorResponseResult?.data ?? responseText, null, 2)}`
|
|
654
|
+
);
|
|
655
|
+
this.response = response;
|
|
656
|
+
}
|
|
657
|
+
};
|
|
658
|
+
|
|
659
|
+
// src/error/Openid4vciSendNotificationError.ts
|
|
660
|
+
var Openid4vciSendNotificationError = class extends Openid4vciError {
|
|
661
|
+
constructor(message, response) {
|
|
662
|
+
super(message);
|
|
663
|
+
this.response = response;
|
|
664
|
+
}
|
|
665
|
+
};
|
|
666
|
+
|
|
667
|
+
// src/metadata/credential-issuer/credential-configurations.ts
|
|
668
|
+
var import_oauth24 = require("@openid4vc/oauth2");
|
|
669
|
+
var import_utils5 = require("@openid4vc/utils");
|
|
670
|
+
function extractScopesForCredentialConfigurationIds(options) {
|
|
671
|
+
const scopes = /* @__PURE__ */ new Set();
|
|
672
|
+
for (const credentialConfigurationId of options.credentialConfigurationIds) {
|
|
673
|
+
const credentialConfiguration = options.issuerMetadata.credentialIssuer.credential_configurations_supported[credentialConfigurationId];
|
|
674
|
+
if (!credentialConfiguration) {
|
|
675
|
+
throw new import_oauth24.Oauth2Error(
|
|
676
|
+
`Credential configuration with id '${credentialConfigurationId}' not found in metadata from credential issuer '${options.issuerMetadata.credentialIssuer.credential_issuer}'`
|
|
677
|
+
);
|
|
678
|
+
}
|
|
679
|
+
const scope = credentialConfiguration.scope;
|
|
680
|
+
if (scope) scopes.add(scope);
|
|
681
|
+
else if (!scope && options.throwOnConfigurationWithoutScope) {
|
|
682
|
+
throw new import_oauth24.Oauth2Error(
|
|
683
|
+
`Credential configuration with id '${credentialConfigurationId}' does not have a 'scope' configured, and 'throwOnConfigurationWithoutScope' was enabled.`
|
|
684
|
+
);
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
return scopes.size > 0 ? Array.from(scopes) : void 0;
|
|
688
|
+
}
|
|
689
|
+
function credentialsSupportedToCredentialConfigurationsSupported(credentialsSupported) {
|
|
690
|
+
const credentialConfigurationsSupported = {};
|
|
691
|
+
for (let index = 0; index < credentialsSupported.length; index++) {
|
|
692
|
+
const credentialSupported = credentialsSupported[index];
|
|
693
|
+
if (!credentialSupported.id) {
|
|
694
|
+
throw new Openid4vciError(
|
|
695
|
+
`Credential supported at index '${index}' does not have an 'id' property. Credential configuration requires the 'id' property as key`
|
|
696
|
+
);
|
|
697
|
+
}
|
|
698
|
+
const parseResult = zCredentialConfigurationSupportedDraft11To14.safeParse(credentialSupported);
|
|
699
|
+
if (!parseResult.success) {
|
|
700
|
+
throw new import_utils5.ValidationError(
|
|
701
|
+
`Error transforming credential supported with id '${credentialSupported.id}' to credential configuration supported format`,
|
|
702
|
+
parseResult.error
|
|
703
|
+
);
|
|
704
|
+
}
|
|
705
|
+
credentialConfigurationsSupported[credentialSupported.id] = parseResult.data;
|
|
706
|
+
}
|
|
707
|
+
return credentialConfigurationsSupported;
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
// src/Openid4vciClient.ts
|
|
711
|
+
var import_oauth218 = require("@openid4vc/oauth2");
|
|
712
|
+
|
|
713
|
+
// src/credential-offer/credential-offer.ts
|
|
714
|
+
var import_oauth26 = require("@openid4vc/oauth2");
|
|
715
|
+
var import_utils6 = require("@openid4vc/utils");
|
|
716
|
+
|
|
717
|
+
// src/credential-offer/z-credential-offer.ts
|
|
718
|
+
var import_oauth25 = require("@openid4vc/oauth2");
|
|
719
|
+
var import_zod11 = __toESM(require("zod"));
|
|
720
|
+
|
|
721
|
+
// ../utils/src/validation.ts
|
|
722
|
+
var import_zod10 = __toESM(require("zod"));
|
|
723
|
+
|
|
724
|
+
// ../utils/src/config.ts
|
|
725
|
+
var GLOBAL_CONFIG = {
|
|
726
|
+
allowInsecureUrls: false
|
|
727
|
+
};
|
|
728
|
+
function getGlobalConfig() {
|
|
729
|
+
return GLOBAL_CONFIG;
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
// ../utils/src/validation.ts
|
|
733
|
+
var zHttpsUrl2 = import_zod10.default.string().url().refine(
|
|
734
|
+
(url) => {
|
|
735
|
+
const { allowInsecureUrls } = getGlobalConfig();
|
|
736
|
+
return allowInsecureUrls ? url.startsWith("http://") || url.startsWith("https://") : url.startsWith("https://");
|
|
737
|
+
},
|
|
738
|
+
{ message: "url must be an https:// url" }
|
|
739
|
+
);
|
|
740
|
+
var zInteger2 = import_zod10.default.number().int();
|
|
741
|
+
var zHttpMethod = import_zod10.default.enum(["GET", "POST", "PUT", "DELETE", "HEAD", "OPTIONS", "TRACE", "CONNECT", "PATCH"]);
|
|
742
|
+
|
|
743
|
+
// src/credential-offer/z-credential-offer.ts
|
|
744
|
+
var zTxCode = import_zod11.default.object({
|
|
745
|
+
input_mode: import_zod11.default.union([import_zod11.default.literal("numeric"), import_zod11.default.literal("text")]).optional(),
|
|
746
|
+
length: import_zod11.default.number().int().optional(),
|
|
747
|
+
description: import_zod11.default.string().max(300).optional()
|
|
748
|
+
}).passthrough();
|
|
749
|
+
var zCredentialOfferGrants = import_zod11.default.object({
|
|
750
|
+
authorization_code: import_zod11.default.object({
|
|
751
|
+
issuer_state: import_zod11.default.string().optional(),
|
|
752
|
+
authorization_server: zHttpsUrl2.optional()
|
|
753
|
+
}).passthrough().optional(),
|
|
754
|
+
[import_oauth25.preAuthorizedCodeGrantIdentifier]: import_zod11.default.object({
|
|
755
|
+
"pre-authorized_code": import_zod11.default.string(),
|
|
756
|
+
tx_code: zTxCode.optional(),
|
|
757
|
+
authorization_server: zHttpsUrl2.optional()
|
|
758
|
+
}).passthrough().optional()
|
|
759
|
+
}).passthrough();
|
|
760
|
+
var zCredentialOfferObjectDraft14 = import_zod11.default.object({
|
|
761
|
+
credential_issuer: zHttpsUrl2,
|
|
762
|
+
credential_configuration_ids: import_zod11.default.array(import_zod11.default.string()),
|
|
763
|
+
grants: import_zod11.default.optional(zCredentialOfferGrants)
|
|
764
|
+
}).passthrough();
|
|
765
|
+
var zCredentialOfferObjectDraft11To14 = import_zod11.default.object({
|
|
766
|
+
credential_issuer: zHttpsUrl2,
|
|
767
|
+
// We don't support the inline offer objects from draft 11
|
|
768
|
+
credentials: import_zod11.default.array(
|
|
769
|
+
import_zod11.default.string({ message: "Only string credential identifiers are supported for draft 11 credential offers" })
|
|
770
|
+
),
|
|
771
|
+
grants: import_zod11.default.optional(
|
|
772
|
+
import_zod11.default.object({
|
|
773
|
+
// Has extra param in draft 14, but doesn't matter for transform purposes
|
|
774
|
+
authorization_code: zCredentialOfferGrants.shape.authorization_code,
|
|
775
|
+
[import_oauth25.preAuthorizedCodeGrantIdentifier]: import_zod11.default.object({
|
|
776
|
+
"pre-authorized_code": import_zod11.default.string(),
|
|
777
|
+
user_pin_required: import_zod11.default.optional(import_zod11.default.boolean())
|
|
778
|
+
}).passthrough().optional()
|
|
779
|
+
})
|
|
780
|
+
)
|
|
781
|
+
}).passthrough().transform(({ credentials, grants, ...rest }) => {
|
|
782
|
+
const v14 = {
|
|
783
|
+
...rest,
|
|
784
|
+
credential_configuration_ids: credentials
|
|
785
|
+
};
|
|
786
|
+
if (grants) {
|
|
787
|
+
v14.grants = { ...grants };
|
|
788
|
+
if (grants[import_oauth25.preAuthorizedCodeGrantIdentifier]) {
|
|
789
|
+
const { user_pin_required, ...restGrants } = grants[import_oauth25.preAuthorizedCodeGrantIdentifier];
|
|
790
|
+
v14.grants[import_oauth25.preAuthorizedCodeGrantIdentifier] = {
|
|
791
|
+
...restGrants
|
|
792
|
+
};
|
|
793
|
+
if (user_pin_required) {
|
|
794
|
+
v14.grants[import_oauth25.preAuthorizedCodeGrantIdentifier].tx_code = {
|
|
795
|
+
input_mode: "text"
|
|
796
|
+
};
|
|
797
|
+
}
|
|
798
|
+
}
|
|
799
|
+
}
|
|
800
|
+
return v14;
|
|
801
|
+
}).pipe(zCredentialOfferObjectDraft14);
|
|
802
|
+
var zCredentialOfferObject = import_zod11.default.union([
|
|
803
|
+
// First prioritize draft 14 (and 13)
|
|
804
|
+
zCredentialOfferObjectDraft14,
|
|
805
|
+
// Then try parsing draft 11 and transform into draft 14
|
|
806
|
+
zCredentialOfferObjectDraft11To14
|
|
807
|
+
]);
|
|
808
|
+
|
|
809
|
+
// src/credential-offer/credential-offer.ts
|
|
810
|
+
async function resolveCredentialOffer(credentialOffer, options) {
|
|
811
|
+
const parsedQueryParams = (0, import_utils6.getQueryParams)(credentialOffer);
|
|
812
|
+
let credentialOfferParseResult;
|
|
813
|
+
if (parsedQueryParams.credential_offer_uri) {
|
|
814
|
+
const fetchWithZod = (0, import_utils6.createZodFetcher)(options?.fetch);
|
|
815
|
+
const { response, result } = await fetchWithZod(
|
|
816
|
+
zCredentialOfferObject,
|
|
817
|
+
import_utils6.ContentType.Json,
|
|
818
|
+
parsedQueryParams.credential_offer_uri
|
|
819
|
+
);
|
|
820
|
+
if (!response.ok || !result) {
|
|
821
|
+
throw new import_oauth26.InvalidFetchResponseError(
|
|
822
|
+
`Fetching credential offer from '${parsedQueryParams.credential_offer_uri}' resulted in an unsuccesfull response with status '${response.status}'`,
|
|
823
|
+
await response.clone().text(),
|
|
824
|
+
response
|
|
825
|
+
);
|
|
826
|
+
}
|
|
827
|
+
credentialOfferParseResult = result;
|
|
828
|
+
} else if (parsedQueryParams.credential_offer) {
|
|
829
|
+
let credentialOfferJson;
|
|
830
|
+
try {
|
|
831
|
+
credentialOfferJson = JSON.parse(decodeURIComponent(parsedQueryParams.credential_offer));
|
|
832
|
+
} catch (error) {
|
|
833
|
+
throw new import_oauth26.Oauth2Error(`Error parsing JSON from 'credential_offer' param in credential offer '${credentialOffer}'`);
|
|
834
|
+
}
|
|
835
|
+
credentialOfferParseResult = zCredentialOfferObject.safeParse(credentialOfferJson);
|
|
836
|
+
} else {
|
|
837
|
+
throw new import_oauth26.Oauth2Error(`Credential offer did not contain either 'credential_offer' or 'credential_offer_uri' param.`);
|
|
838
|
+
}
|
|
839
|
+
if (credentialOfferParseResult.error) {
|
|
840
|
+
throw new import_utils6.ValidationError(
|
|
841
|
+
`Error parsing credential offer in draft 11, 13 or 14 format extracted from credential offer '${credentialOffer}'`,
|
|
842
|
+
credentialOfferParseResult.error
|
|
843
|
+
);
|
|
844
|
+
}
|
|
845
|
+
return credentialOfferParseResult.data;
|
|
846
|
+
}
|
|
847
|
+
function determineAuthorizationServerForCredentialOffer(options) {
|
|
848
|
+
const authorizationServers = options.issuerMetadata.credentialIssuer.authorization_servers;
|
|
849
|
+
let authorizationServer;
|
|
850
|
+
if (options.grantAuthorizationServer) {
|
|
851
|
+
authorizationServer = options.grantAuthorizationServer;
|
|
852
|
+
if (!authorizationServers) {
|
|
853
|
+
throw new import_oauth26.Oauth2Error(
|
|
854
|
+
`Credential offer grant contains 'authorization_server' with value '${options.grantAuthorizationServer}' but credential issuer metadata does not have an 'authorization_servers' property to match the value against.`
|
|
855
|
+
);
|
|
856
|
+
}
|
|
857
|
+
if (!authorizationServers.includes(authorizationServer)) {
|
|
858
|
+
throw new import_oauth26.Oauth2Error(
|
|
859
|
+
`Credential offer grant contains 'authorization_server' with value '${options.grantAuthorizationServer}' but credential issuer metadata does not include this authorization server. Available 'authorization_server' values are ${authorizationServers.join(", ")}.`
|
|
860
|
+
);
|
|
861
|
+
}
|
|
862
|
+
} else if (!authorizationServers) {
|
|
863
|
+
authorizationServer = options.issuerMetadata.credentialIssuer.credential_issuer;
|
|
864
|
+
} else {
|
|
865
|
+
if (authorizationServers.length === 0) {
|
|
866
|
+
throw new import_oauth26.Oauth2Error(`Credential issuer metadata has 'authorization_servers' value with length of 0`);
|
|
867
|
+
}
|
|
868
|
+
if (authorizationServers.length > 1) {
|
|
869
|
+
throw new import_oauth26.Oauth2Error(
|
|
870
|
+
`Credential issuer metadata has 'authorization_server' with multiple entries, but the credential offer grant did not specify which authorization server to use.`
|
|
871
|
+
);
|
|
872
|
+
}
|
|
873
|
+
authorizationServer = authorizationServers[0];
|
|
874
|
+
}
|
|
875
|
+
return authorizationServer;
|
|
876
|
+
}
|
|
877
|
+
async function createCredentialOffer(options) {
|
|
878
|
+
const {
|
|
879
|
+
[import_oauth26.preAuthorizedCodeGrantIdentifier]: preAuthorizedCodeGrant,
|
|
880
|
+
[import_oauth26.authorizationCodeGrantIdentifier]: authorizationCodeGrant,
|
|
881
|
+
...restGrants
|
|
882
|
+
} = options.grants;
|
|
883
|
+
const grants = { ...restGrants };
|
|
884
|
+
if (authorizationCodeGrant) {
|
|
885
|
+
determineAuthorizationServerForCredentialOffer({
|
|
886
|
+
issuerMetadata: options.issuerMetadata,
|
|
887
|
+
grantAuthorizationServer: authorizationCodeGrant.authorization_server
|
|
888
|
+
});
|
|
889
|
+
grants[import_oauth26.authorizationCodeGrantIdentifier] = authorizationCodeGrant;
|
|
890
|
+
}
|
|
891
|
+
if (preAuthorizedCodeGrant) {
|
|
892
|
+
determineAuthorizationServerForCredentialOffer({
|
|
893
|
+
issuerMetadata: options.issuerMetadata,
|
|
894
|
+
grantAuthorizationServer: preAuthorizedCodeGrant.authorization_server
|
|
895
|
+
});
|
|
896
|
+
grants[import_oauth26.preAuthorizedCodeGrantIdentifier] = {
|
|
897
|
+
...preAuthorizedCodeGrant,
|
|
898
|
+
"pre-authorized_code": preAuthorizedCodeGrant["pre-authorized_code"] ?? (0, import_utils6.encodeToBase64Url)(await options.callbacks.generateRandom(32))
|
|
899
|
+
};
|
|
900
|
+
const txCode = grants[import_oauth26.preAuthorizedCodeGrantIdentifier].tx_code;
|
|
901
|
+
if (txCode && options.issuerMetadata.originalDraftVersion === "Draft11" /* Draft11 */) {
|
|
902
|
+
grants[import_oauth26.preAuthorizedCodeGrantIdentifier].user_pin_required = txCode !== void 0;
|
|
903
|
+
}
|
|
904
|
+
}
|
|
905
|
+
const idsNotInMetadata = options.credentialConfigurationIds.filter(
|
|
906
|
+
(id) => options.issuerMetadata.credentialIssuer.credential_configurations_supported[id] === void 0
|
|
907
|
+
);
|
|
908
|
+
if (idsNotInMetadata.length > 0) {
|
|
909
|
+
throw new import_oauth26.Oauth2Error(
|
|
910
|
+
`Credential configuration ids ${idsNotInMetadata} not found in the credential issuer metadata 'credential_configurations_supported'. Available ids are ${Object.keys(options.issuerMetadata.credentialIssuer.credential_configurations_supported).join(", ")}.`
|
|
911
|
+
);
|
|
912
|
+
}
|
|
913
|
+
const credentialOfferScheme = options.credentialOfferScheme ?? "openid-credential-offer://";
|
|
914
|
+
const credentialOfferObject = (0, import_utils6.parseWithErrorHandling)(zCredentialOfferObject, {
|
|
915
|
+
credential_issuer: options.issuerMetadata.credentialIssuer.credential_issuer,
|
|
916
|
+
credential_configuration_ids: options.credentialConfigurationIds,
|
|
917
|
+
grants,
|
|
918
|
+
...options.additionalPayload
|
|
919
|
+
});
|
|
920
|
+
if (options.issuerMetadata.originalDraftVersion === "Draft11" /* Draft11 */) {
|
|
921
|
+
credentialOfferObject.credentials = credentialOfferObject.credential_configuration_ids;
|
|
922
|
+
}
|
|
923
|
+
const url = new import_utils6.URL(credentialOfferScheme);
|
|
924
|
+
url.search = `?${new import_utils6.URLSearchParams([
|
|
925
|
+
...url.searchParams.entries(),
|
|
926
|
+
...(0, import_utils6.objectToQueryParams)({
|
|
927
|
+
credential_offer_uri: options.credentialOfferUri,
|
|
928
|
+
// Only add credential_offer is uri is undefined
|
|
929
|
+
credential_offer: options.credentialOfferUri ? void 0 : credentialOfferObject
|
|
930
|
+
}).entries()
|
|
931
|
+
]).toString()}`;
|
|
932
|
+
return {
|
|
933
|
+
credentialOffer: url.toString(),
|
|
934
|
+
credentialOfferObject
|
|
935
|
+
};
|
|
936
|
+
}
|
|
937
|
+
|
|
938
|
+
// src/credential-request/format-payload.ts
|
|
939
|
+
var import_utils7 = require("@openid4vc/utils");
|
|
940
|
+
function getCredentialRequestFormatPayloadForCredentialConfigurationId(options) {
|
|
941
|
+
const credentialConfiguration = options.issuerMetadata.credentialIssuer.credential_configurations_supported[options.credentialConfigurationId];
|
|
942
|
+
if (!credentialConfiguration) {
|
|
943
|
+
throw new Openid4vciError(
|
|
944
|
+
`Could not find credential configuration with id '${options.credentialConfigurationId}' in metadata of credential issuer '${options.issuerMetadata.credentialIssuer.credential_issuer}'.`
|
|
945
|
+
);
|
|
946
|
+
}
|
|
947
|
+
if ((0, import_utils7.zIs)(zSdJwtVcCredentialIssuerMetadata, credentialConfiguration)) {
|
|
948
|
+
return {
|
|
949
|
+
format: credentialConfiguration.format,
|
|
950
|
+
vct: credentialConfiguration.vct
|
|
951
|
+
};
|
|
952
|
+
}
|
|
953
|
+
if ((0, import_utils7.zIs)(zMsoMdocCredentialIssuerMetadata, credentialConfiguration)) {
|
|
954
|
+
return {
|
|
955
|
+
format: credentialConfiguration.format,
|
|
956
|
+
doctype: credentialConfiguration.doctype
|
|
957
|
+
};
|
|
958
|
+
}
|
|
959
|
+
if ((0, import_utils7.zIs)(zLdpVcCredentialIssuerMetadata, credentialConfiguration)) {
|
|
960
|
+
return {
|
|
961
|
+
format: credentialConfiguration.format,
|
|
962
|
+
credential_definition: {
|
|
963
|
+
"@context": credentialConfiguration.credential_definition["@context"],
|
|
964
|
+
type: credentialConfiguration.credential_definition.type
|
|
965
|
+
}
|
|
966
|
+
};
|
|
967
|
+
}
|
|
968
|
+
if ((0, import_utils7.zIs)(zJwtVcJsonLdCredentialIssuerMetadata, credentialConfiguration)) {
|
|
969
|
+
return {
|
|
970
|
+
format: credentialConfiguration.format,
|
|
971
|
+
credential_definition: {
|
|
972
|
+
"@context": credentialConfiguration.credential_definition["@context"],
|
|
973
|
+
type: credentialConfiguration.credential_definition.type
|
|
974
|
+
}
|
|
975
|
+
};
|
|
976
|
+
}
|
|
977
|
+
if ((0, import_utils7.zIs)(zJwtVcJsonCredentialIssuerMetadata, credentialConfiguration)) {
|
|
978
|
+
return {
|
|
979
|
+
format: credentialConfiguration.format,
|
|
980
|
+
credential_definition: {
|
|
981
|
+
type: credentialConfiguration.credential_definition.type
|
|
982
|
+
}
|
|
983
|
+
};
|
|
984
|
+
}
|
|
985
|
+
throw new Openid4vciError(
|
|
986
|
+
`Unknown format '${credentialConfiguration.format}' in credential configuration with id '${options.credentialConfigurationId}' for credential issuer '${options.issuerMetadata.credentialIssuer.credential_issuer}'`
|
|
987
|
+
);
|
|
988
|
+
}
|
|
989
|
+
|
|
990
|
+
// src/credential-request/retrieve-credentials.ts
|
|
991
|
+
var import_oauth210 = require("@openid4vc/oauth2");
|
|
992
|
+
var import_utils9 = require("@openid4vc/utils");
|
|
993
|
+
|
|
994
|
+
// src/credential-request/z-credential-request.ts
|
|
995
|
+
var import_zod15 = __toESM(require("zod"));
|
|
996
|
+
|
|
997
|
+
// src/credential-request/z-credential-request-common.ts
|
|
998
|
+
var import_oauth29 = require("@openid4vc/oauth2");
|
|
999
|
+
var import_zod14 = __toESM(require("zod"));
|
|
1000
|
+
|
|
1001
|
+
// src/formats/proof-type/jwt/z-jwt-proof-type.ts
|
|
1002
|
+
var import_oauth27 = require("@openid4vc/oauth2");
|
|
1003
|
+
var import_utils8 = require("@openid4vc/utils");
|
|
1004
|
+
var import_zod12 = __toESM(require("zod"));
|
|
1005
|
+
var zJwtProofTypeIdentifier = import_zod12.default.literal("jwt");
|
|
1006
|
+
var jwtProofTypeIdentifier = zJwtProofTypeIdentifier.value;
|
|
1007
|
+
var zCredentialRequestProofJwt = import_zod12.default.object({
|
|
1008
|
+
proof_type: zJwtProofTypeIdentifier,
|
|
1009
|
+
jwt: import_oauth27.zCompactJwt
|
|
1010
|
+
});
|
|
1011
|
+
var zCredentialRequestJwtProofTypeHeader = import_oauth27.zJwtHeader.merge(
|
|
1012
|
+
import_zod12.default.object({
|
|
1013
|
+
key_attestation: import_zod12.default.optional(import_oauth27.zCompactJwt),
|
|
1014
|
+
typ: import_zod12.default.literal("openid4vci-proof+jwt")
|
|
1015
|
+
})
|
|
1016
|
+
).passthrough().refine(({ kid, jwk }) => jwk === void 0 || kid === void 0, {
|
|
1017
|
+
message: `Both 'jwk' and 'kid' are defined. Only one is allowed`
|
|
1018
|
+
}).refine(({ trust_chain, kid }) => !trust_chain || !kid, {
|
|
1019
|
+
message: `When 'trust_chain' is provided, 'kid' is required`
|
|
1020
|
+
});
|
|
1021
|
+
var zCredentialRequestJwtProofTypePayload = import_zod12.default.object({
|
|
1022
|
+
...import_oauth27.zJwtPayload.shape,
|
|
1023
|
+
aud: import_utils8.zHttpsUrl,
|
|
1024
|
+
iat: import_utils8.zInteger
|
|
1025
|
+
}).passthrough();
|
|
1026
|
+
|
|
1027
|
+
// src/formats/proof-type/attestation/z-attestation-proof-type.ts
|
|
1028
|
+
var import_oauth28 = require("@openid4vc/oauth2");
|
|
1029
|
+
var import_zod13 = __toESM(require("zod"));
|
|
1030
|
+
var zAttestationProofTypeIdentifier = import_zod13.default.literal("attestation");
|
|
1031
|
+
var attestationProofTypeIdentifier = zAttestationProofTypeIdentifier.value;
|
|
1032
|
+
var zCredentialRequestProofAttestation = import_zod13.default.object({
|
|
1033
|
+
proof_type: zAttestationProofTypeIdentifier,
|
|
1034
|
+
attestation: import_oauth28.zCompactJwt
|
|
1035
|
+
});
|
|
1036
|
+
var zCredentialRequestAttestationProofTypePayload = zKeyAttestationJwtPayloadForUse("proof_type.attestation");
|
|
1037
|
+
|
|
1038
|
+
// src/credential-request/z-credential-request-common.ts
|
|
1039
|
+
var zCredentialRequestProofCommon = import_zod14.default.object({
|
|
1040
|
+
proof_type: import_zod14.default.string()
|
|
1041
|
+
}).passthrough();
|
|
1042
|
+
var allCredentialRequestProofs = [zCredentialRequestProofJwt, zCredentialRequestProofAttestation];
|
|
1043
|
+
var zCredentialRequestProof = import_zod14.default.union([
|
|
1044
|
+
zCredentialRequestProofCommon,
|
|
1045
|
+
import_zod14.default.discriminatedUnion("proof_type", allCredentialRequestProofs)
|
|
1046
|
+
]);
|
|
1047
|
+
var zCredentialRequestProofsCommon = import_zod14.default.record(import_zod14.default.string(), import_zod14.default.array(import_zod14.default.unknown()));
|
|
1048
|
+
var zCredentialRequestProofs = import_zod14.default.object({
|
|
1049
|
+
[zJwtProofTypeIdentifier.value]: import_zod14.default.optional(import_zod14.default.array(zCredentialRequestProofJwt.shape.jwt)),
|
|
1050
|
+
[zAttestationProofTypeIdentifier.value]: import_zod14.default.optional(import_zod14.default.array(zCredentialRequestProofAttestation.shape.attestation))
|
|
1051
|
+
});
|
|
1052
|
+
var zCredentialRequestCommon = import_zod14.default.object({
|
|
1053
|
+
proof: zCredentialRequestProof.optional(),
|
|
1054
|
+
proofs: import_zod14.default.optional(
|
|
1055
|
+
import_zod14.default.intersection(zCredentialRequestProofsCommon, zCredentialRequestProofs).refine((proofs) => Object.values(proofs).length === 1, {
|
|
1056
|
+
message: `The 'proofs' object in a credential request should contain exactly one attribute`
|
|
1057
|
+
})
|
|
1058
|
+
),
|
|
1059
|
+
credential_response_encryption: import_zod14.default.object({
|
|
1060
|
+
jwk: import_oauth29.zJwk,
|
|
1061
|
+
alg: import_zod14.default.string(),
|
|
1062
|
+
enc: import_zod14.default.string()
|
|
1063
|
+
}).passthrough().optional()
|
|
1064
|
+
}).passthrough().refine(({ proof, proofs }) => !(proof !== void 0 && proofs !== void 0), {
|
|
1065
|
+
message: `Both 'proof' and 'proofs' are defined. Only one is allowed`
|
|
1066
|
+
});
|
|
1067
|
+
|
|
1068
|
+
// src/credential-request/z-credential-request.ts
|
|
1069
|
+
var allCredentialRequestFormats = [
|
|
1070
|
+
zSdJwtVcCredentialRequestFormat,
|
|
1071
|
+
zMsoMdocCredentialRequestFormat,
|
|
1072
|
+
zLdpVcCredentialRequestFormat,
|
|
1073
|
+
zJwtVcJsonLdCredentialRequestFormat,
|
|
1074
|
+
zJwtVcJsonCredentialRequestFormat
|
|
1075
|
+
];
|
|
1076
|
+
var allCredentialRequestFormatIdentifiers = allCredentialRequestFormats.map(
|
|
1077
|
+
(format) => format.shape.format.value
|
|
1078
|
+
);
|
|
1079
|
+
var zAuthorizationDetailsCredentialRequest = import_zod15.default.object({
|
|
1080
|
+
credential_identifier: import_zod15.default.string(),
|
|
1081
|
+
// Cannot be present if credential identifier is present
|
|
1082
|
+
format: import_zod15.default.never({ message: "'format' cannot be defined when 'credential_identifier' is set." }).optional()
|
|
1083
|
+
});
|
|
1084
|
+
var zCredentialRequestFormatNoCredentialIdentifier = import_zod15.default.object({
|
|
1085
|
+
format: import_zod15.default.string(),
|
|
1086
|
+
credential_identifier: import_zod15.default.never({ message: "'credential_identifier' cannot be defined when 'format' is set." }).optional()
|
|
1087
|
+
}).passthrough();
|
|
1088
|
+
var zCredenialRequestDraft14WithFormat = zCredentialRequestCommon.and(zCredentialRequestFormatNoCredentialIdentifier).transform((data, ctx) => {
|
|
1089
|
+
if (!allCredentialRequestFormatIdentifiers.includes(data.format)) return data;
|
|
1090
|
+
const result = import_zod15.default.object({}).passthrough().and(import_zod15.default.discriminatedUnion("format", allCredentialRequestFormats)).safeParse(data);
|
|
1091
|
+
if (result.success) {
|
|
1092
|
+
return result.data;
|
|
1093
|
+
}
|
|
1094
|
+
for (const issue of result.error.issues) {
|
|
1095
|
+
ctx.addIssue(issue);
|
|
1096
|
+
}
|
|
1097
|
+
return import_zod15.default.NEVER;
|
|
1098
|
+
});
|
|
1099
|
+
var zCredentialRequestDraft14 = import_zod15.default.union([
|
|
1100
|
+
zCredenialRequestDraft14WithFormat,
|
|
1101
|
+
zCredentialRequestCommon.and(zAuthorizationDetailsCredentialRequest)
|
|
1102
|
+
]);
|
|
1103
|
+
var zCredentialRequestDraft11To14 = zCredentialRequestCommon.and(zCredentialRequestFormatNoCredentialIdentifier).transform((data, ctx) => {
|
|
1104
|
+
const formatSpecificTransformations = {
|
|
1105
|
+
[zLdpVcFormatIdentifier.value]: zLdpVcCredentialRequestDraft11To14,
|
|
1106
|
+
[zJwtVcJsonFormatIdentifier.value]: zJwtVcJsonCredentialRequestDraft11To14,
|
|
1107
|
+
[zJwtVcJsonLdFormatIdentifier.value]: zJwtVcJsonLdCredentialRequestDraft11To14
|
|
1108
|
+
};
|
|
1109
|
+
if (!Object.keys(formatSpecificTransformations).includes(data.format)) return data;
|
|
1110
|
+
const schema = formatSpecificTransformations[data.format];
|
|
1111
|
+
const result = schema.safeParse(data);
|
|
1112
|
+
if (result.success) return result.data;
|
|
1113
|
+
for (const issue of result.error.issues) {
|
|
1114
|
+
ctx.addIssue(issue);
|
|
1115
|
+
}
|
|
1116
|
+
return import_zod15.default.NEVER;
|
|
1117
|
+
}).pipe(zCredentialRequestDraft14);
|
|
1118
|
+
var zCredentialRequestDraft14To11 = zCredentialRequestDraft14.refine(
|
|
1119
|
+
(data) => data.credential_identifier === void 0,
|
|
1120
|
+
`'credential_identifier' is not supported in OpenID4VCI draft 11`
|
|
1121
|
+
).transform((data, ctx) => {
|
|
1122
|
+
const formatSpecificTransformations = {
|
|
1123
|
+
[zLdpVcFormatIdentifier.value]: zLdpVcCredentialRequestDraft14To11,
|
|
1124
|
+
[zJwtVcJsonFormatIdentifier.value]: zJwtVcJsonCredentialRequestDraft14To11,
|
|
1125
|
+
[zJwtVcJsonLdFormatIdentifier.value]: zJwtVcJsonLdCredentialRequestDraft14To11
|
|
1126
|
+
};
|
|
1127
|
+
if (!Object.keys(formatSpecificTransformations).includes(data.format)) return data;
|
|
1128
|
+
const schema = formatSpecificTransformations[data.format];
|
|
1129
|
+
const result = schema.safeParse(data);
|
|
1130
|
+
if (result.success) return result.data;
|
|
1131
|
+
for (const issue of result.error.issues) {
|
|
1132
|
+
ctx.addIssue(issue);
|
|
1133
|
+
}
|
|
1134
|
+
return import_zod15.default.NEVER;
|
|
1135
|
+
});
|
|
1136
|
+
var zCredentialRequest = import_zod15.default.union([zCredentialRequestDraft14, zCredentialRequestDraft11To14]);
|
|
1137
|
+
|
|
1138
|
+
// src/credential-request/z-credential-response.ts
|
|
1139
|
+
var import_zod17 = __toESM(require("zod"));
|
|
1140
|
+
|
|
1141
|
+
// ../oauth2/src/common/z-oauth2-error.ts
|
|
1142
|
+
var import_zod16 = __toESM(require("zod"));
|
|
1143
|
+
var Oauth2ErrorCodes = /* @__PURE__ */ ((Oauth2ErrorCodes4) => {
|
|
1144
|
+
Oauth2ErrorCodes4["ServerError"] = "server_error";
|
|
1145
|
+
Oauth2ErrorCodes4["InvalidTarget"] = "invalid_target";
|
|
1146
|
+
Oauth2ErrorCodes4["InvalidRequest"] = "invalid_request";
|
|
1147
|
+
Oauth2ErrorCodes4["InvalidToken"] = "invalid_token";
|
|
1148
|
+
Oauth2ErrorCodes4["InsufficientScope"] = "insufficient_scope";
|
|
1149
|
+
Oauth2ErrorCodes4["InvalidGrant"] = "invalid_grant";
|
|
1150
|
+
Oauth2ErrorCodes4["InvalidClient"] = "invalid_client";
|
|
1151
|
+
Oauth2ErrorCodes4["UnauthorizedClient"] = "unauthorized_client";
|
|
1152
|
+
Oauth2ErrorCodes4["UnsupportedGrantType"] = "unsupported_grant_type";
|
|
1153
|
+
Oauth2ErrorCodes4["InvalidScope"] = "invalid_scope";
|
|
1154
|
+
Oauth2ErrorCodes4["InvalidDpopProof"] = "invalid_dpop_proof";
|
|
1155
|
+
Oauth2ErrorCodes4["UseDpopNonce"] = "use_dpop_nonce";
|
|
1156
|
+
Oauth2ErrorCodes4["RedirectToWeb"] = "redirect_to_web";
|
|
1157
|
+
Oauth2ErrorCodes4["InvalidSession"] = "invalid_session";
|
|
1158
|
+
Oauth2ErrorCodes4["InsufficientAuthorization"] = "insufficient_authorization";
|
|
1159
|
+
Oauth2ErrorCodes4["InvalidCredentialRequest"] = "invalid_credential_request";
|
|
1160
|
+
Oauth2ErrorCodes4["CredentialRequestDenied"] = "credential_request_denied";
|
|
1161
|
+
Oauth2ErrorCodes4["UnsupportedCredentialType"] = "unsupported_credential_type";
|
|
1162
|
+
Oauth2ErrorCodes4["UnsupportedCredentialFormat"] = "unsupported_credential_format";
|
|
1163
|
+
Oauth2ErrorCodes4["InvalidProof"] = "invalid_proof";
|
|
1164
|
+
Oauth2ErrorCodes4["InvalidNonce"] = "invalid_nonce";
|
|
1165
|
+
Oauth2ErrorCodes4["InvalidEncryptionParameters"] = "invalid_encryption_parameters";
|
|
1166
|
+
Oauth2ErrorCodes4["InvalidRequestUri"] = "invalid_request_uri";
|
|
1167
|
+
Oauth2ErrorCodes4["InvalidRequestObject"] = "invalid_request_object";
|
|
1168
|
+
Oauth2ErrorCodes4["RequestNotSupported"] = "request_not_supported";
|
|
1169
|
+
Oauth2ErrorCodes4["RequestUriNotSupported"] = "request_uri_not_supported";
|
|
1170
|
+
Oauth2ErrorCodes4["VpFormatsNotSupported"] = "vp_formats_not_supported";
|
|
1171
|
+
Oauth2ErrorCodes4["AccessDenied"] = "access_denied";
|
|
1172
|
+
Oauth2ErrorCodes4["InvalidPresentationDefinitionUri"] = "invalid_presentation_definition_uri";
|
|
1173
|
+
Oauth2ErrorCodes4["InvalidPresentationDefinitionReference"] = "invalid_presentation_definition_reference";
|
|
1174
|
+
Oauth2ErrorCodes4["InvalidRequestUriMethod"] = "invalid_request_uri_method";
|
|
1175
|
+
Oauth2ErrorCodes4["InvalidTransactionData"] = "invalid_transaction_data";
|
|
1176
|
+
Oauth2ErrorCodes4["WalletUnavailable"] = "wallet_unavailable";
|
|
1177
|
+
return Oauth2ErrorCodes4;
|
|
1178
|
+
})(Oauth2ErrorCodes || {});
|
|
1179
|
+
var zOauth2ErrorResponse = import_zod16.default.object({
|
|
1180
|
+
error: import_zod16.default.union([import_zod16.default.nativeEnum(Oauth2ErrorCodes), import_zod16.default.string()]),
|
|
1181
|
+
error_description: import_zod16.default.string().optional(),
|
|
1182
|
+
error_uri: import_zod16.default.string().optional()
|
|
1183
|
+
}).passthrough();
|
|
1184
|
+
|
|
1185
|
+
// src/credential-request/z-credential-response.ts
|
|
1186
|
+
var zCredentialEncoding = import_zod17.default.union([import_zod17.default.string(), import_zod17.default.record(import_zod17.default.string(), import_zod17.default.any())]);
|
|
1187
|
+
var zCredentialResponse = import_zod17.default.object({
|
|
1188
|
+
credential: import_zod17.default.optional(zCredentialEncoding),
|
|
1189
|
+
credentials: import_zod17.default.optional(import_zod17.default.array(zCredentialEncoding)),
|
|
1190
|
+
transaction_id: import_zod17.default.string().optional(),
|
|
1191
|
+
c_nonce: import_zod17.default.string().optional(),
|
|
1192
|
+
c_nonce_expires_in: import_zod17.default.number().int().optional(),
|
|
1193
|
+
notification_id: import_zod17.default.string().optional()
|
|
1194
|
+
}).passthrough().refine(
|
|
1195
|
+
(value) => {
|
|
1196
|
+
const { credential, credentials, transaction_id } = value;
|
|
1197
|
+
return [credential, credentials, transaction_id].filter((i) => i !== void 0).length === 1;
|
|
1198
|
+
},
|
|
1199
|
+
{
|
|
1200
|
+
message: `Exactly one of 'credential', 'credentials', or 'transaction_id' MUST be defined.`
|
|
1201
|
+
}
|
|
1202
|
+
);
|
|
1203
|
+
var zCredentialErrorResponse = import_zod17.default.object({
|
|
1204
|
+
...zOauth2ErrorResponse.shape,
|
|
1205
|
+
c_nonce: import_zod17.default.string().optional(),
|
|
1206
|
+
c_nonce_expires_in: import_zod17.default.number().int().optional()
|
|
1207
|
+
}).passthrough();
|
|
1208
|
+
|
|
1209
|
+
// src/credential-request/retrieve-credentials.ts
|
|
1210
|
+
async function retrieveCredentialsWithFormat(options) {
|
|
1211
|
+
const credentialRequest = {
|
|
1212
|
+
...options.formatPayload,
|
|
1213
|
+
...options.additionalRequestPayload,
|
|
1214
|
+
proof: options.proof,
|
|
1215
|
+
proofs: options.proofs
|
|
1216
|
+
};
|
|
1217
|
+
return retrieveCredentials({
|
|
1218
|
+
callbacks: options.callbacks,
|
|
1219
|
+
credentialRequest,
|
|
1220
|
+
issuerMetadata: options.issuerMetadata,
|
|
1221
|
+
accessToken: options.accessToken,
|
|
1222
|
+
dpop: options.dpop
|
|
1223
|
+
});
|
|
1224
|
+
}
|
|
1225
|
+
async function retrieveCredentials(options) {
|
|
1226
|
+
const credentialEndpoint = options.issuerMetadata.credentialIssuer.credential_endpoint;
|
|
1227
|
+
let credentialRequest = (0, import_utils9.parseWithErrorHandling)(
|
|
1228
|
+
zCredentialRequest,
|
|
1229
|
+
options.credentialRequest,
|
|
1230
|
+
"Error validating credential request"
|
|
1231
|
+
);
|
|
1232
|
+
if (credentialRequest.proofs) {
|
|
1233
|
+
const { batch_credential_issuance } = options.issuerMetadata.credentialIssuer;
|
|
1234
|
+
if (!batch_credential_issuance) {
|
|
1235
|
+
throw new import_oauth210.Oauth2Error(
|
|
1236
|
+
`Credential issuer '${options.issuerMetadata.credentialIssuer.credential_issuer}' does not support batch credential issuance using the 'proofs' request property. Only 'proof' is supported.`
|
|
1237
|
+
);
|
|
1238
|
+
}
|
|
1239
|
+
const proofs = Object.values(credentialRequest.proofs)[0];
|
|
1240
|
+
if (proofs.length > batch_credential_issuance.batch_size) {
|
|
1241
|
+
throw new import_oauth210.Oauth2Error(
|
|
1242
|
+
`Credential issuer '${options.issuerMetadata.credentialIssuer.credential_issuer}' supports batch issuance, but the max batch size is '${batch_credential_issuance.batch_size}'. A total of '${proofs.length}' proofs were provided.`
|
|
1243
|
+
);
|
|
1244
|
+
}
|
|
1245
|
+
}
|
|
1246
|
+
if (options.issuerMetadata.originalDraftVersion === "Draft11" /* Draft11 */) {
|
|
1247
|
+
credentialRequest = (0, import_utils9.parseWithErrorHandling)(
|
|
1248
|
+
zCredentialRequestDraft14To11,
|
|
1249
|
+
credentialRequest,
|
|
1250
|
+
`Error transforming credential request from ${"Draft14" /* Draft14 */} to ${"Draft11" /* Draft11 */}`
|
|
1251
|
+
);
|
|
1252
|
+
}
|
|
1253
|
+
const resourceResponse = await (0, import_oauth210.resourceRequest)({
|
|
1254
|
+
dpop: options.dpop,
|
|
1255
|
+
accessToken: options.accessToken,
|
|
1256
|
+
callbacks: options.callbacks,
|
|
1257
|
+
url: credentialEndpoint,
|
|
1258
|
+
requestOptions: {
|
|
1259
|
+
method: "POST",
|
|
1260
|
+
headers: {
|
|
1261
|
+
"Content-Type": import_utils9.ContentType.Json
|
|
1262
|
+
},
|
|
1263
|
+
body: JSON.stringify(credentialRequest)
|
|
1264
|
+
}
|
|
1265
|
+
});
|
|
1266
|
+
if (!resourceResponse.ok) {
|
|
1267
|
+
const credentialErrorResponseResult = (0, import_utils9.isResponseContentType)(import_utils9.ContentType.Json, resourceResponse.response) ? zCredentialErrorResponse.safeParse(await resourceResponse.response.clone().json()) : void 0;
|
|
1268
|
+
return {
|
|
1269
|
+
...resourceResponse,
|
|
1270
|
+
credentialErrorResponseResult
|
|
1271
|
+
};
|
|
1272
|
+
}
|
|
1273
|
+
const credentialResponseResult = (0, import_utils9.isResponseContentType)(import_utils9.ContentType.Json, resourceResponse.response) ? zCredentialResponse.safeParse(await resourceResponse.response.clone().json()) : void 0;
|
|
1274
|
+
if (!credentialResponseResult?.success) {
|
|
1275
|
+
return {
|
|
1276
|
+
...resourceResponse,
|
|
1277
|
+
ok: false,
|
|
1278
|
+
credentialResponseResult
|
|
1279
|
+
};
|
|
1280
|
+
}
|
|
1281
|
+
return {
|
|
1282
|
+
...resourceResponse,
|
|
1283
|
+
credentialResponse: credentialResponseResult.data
|
|
1284
|
+
};
|
|
1285
|
+
}
|
|
1286
|
+
|
|
1287
|
+
// src/formats/proof-type/jwt/jwt-proof-type.ts
|
|
1288
|
+
var import_oauth213 = require("@openid4vc/oauth2");
|
|
1289
|
+
var import_oauth214 = require("@openid4vc/oauth2");
|
|
1290
|
+
var import_utils11 = require("@openid4vc/utils");
|
|
1291
|
+
|
|
1292
|
+
// src/key-attestation/key-attestation.ts
|
|
1293
|
+
var import_oauth211 = require("@openid4vc/oauth2");
|
|
1294
|
+
var import_oauth212 = require("@openid4vc/oauth2");
|
|
1295
|
+
var import_utils10 = require("@openid4vc/utils");
|
|
1296
|
+
async function verifyKeyAttestationJwt(options) {
|
|
1297
|
+
const { header, payload } = (0, import_oauth211.decodeJwt)({
|
|
1298
|
+
jwt: options.keyAttestationJwt,
|
|
1299
|
+
headerSchema: zKeyAttestationJwtHeader,
|
|
1300
|
+
payloadSchema: zKeyAttestationJwtPayloadForUse(options.use)
|
|
1301
|
+
});
|
|
1302
|
+
const now = options.now?.getTime() ?? Date.now();
|
|
1303
|
+
if (options.nonceExpiresAt && now > options.nonceExpiresAt.getTime()) {
|
|
1304
|
+
throw new Openid4vciError("Nonce used for key attestation jwt expired");
|
|
1305
|
+
}
|
|
1306
|
+
const { signer } = await (0, import_oauth212.verifyJwt)({
|
|
1307
|
+
compact: options.keyAttestationJwt,
|
|
1308
|
+
header,
|
|
1309
|
+
payload,
|
|
1310
|
+
signer: (0, import_oauth212.jwtSignerFromJwt)({ header, payload }),
|
|
1311
|
+
verifyJwtCallback: options.callbacks.verifyJwt,
|
|
1312
|
+
errorMessage: "Error verifiying key attestation jwt",
|
|
1313
|
+
expectedNonce: options.expectedNonce,
|
|
1314
|
+
now: options.now
|
|
1315
|
+
});
|
|
1316
|
+
return {
|
|
1317
|
+
header,
|
|
1318
|
+
payload,
|
|
1319
|
+
signer
|
|
1320
|
+
};
|
|
1321
|
+
}
|
|
1322
|
+
|
|
1323
|
+
// src/formats/proof-type/jwt/jwt-proof-type.ts
|
|
1324
|
+
async function createCredentialRequestJwtProof(options) {
|
|
1325
|
+
const header = (0, import_utils11.parseWithErrorHandling)(zCredentialRequestJwtProofTypeHeader, {
|
|
1326
|
+
...(0, import_oauth213.jwtHeaderFromJwtSigner)(options.signer),
|
|
1327
|
+
key_attestation: options.keyAttestationJwt,
|
|
1328
|
+
typ: "openid4vci-proof+jwt"
|
|
1329
|
+
});
|
|
1330
|
+
const payload = (0, import_utils11.parseWithErrorHandling)(zCredentialRequestJwtProofTypePayload, {
|
|
1331
|
+
nonce: options.nonce,
|
|
1332
|
+
aud: options.credentialIssuer,
|
|
1333
|
+
iat: (0, import_utils11.dateToSeconds)(options.issuedAt),
|
|
1334
|
+
iss: options.clientId
|
|
1335
|
+
});
|
|
1336
|
+
const { jwt, signerJwk } = await options.callbacks.signJwt(options.signer, { header, payload });
|
|
1337
|
+
if (options.keyAttestationJwt) {
|
|
1338
|
+
const decodedKeyAttestation = (0, import_oauth213.decodeJwt)({
|
|
1339
|
+
jwt: options.keyAttestationJwt,
|
|
1340
|
+
headerSchema: zKeyAttestationJwtHeader,
|
|
1341
|
+
payloadSchema: zKeyAttestationJwtPayload
|
|
1342
|
+
});
|
|
1343
|
+
const isSigedWithAttestedKey = await (0, import_oauth213.isJwkInSet)({
|
|
1344
|
+
jwk: signerJwk,
|
|
1345
|
+
jwks: decodedKeyAttestation.payload.attested_keys,
|
|
1346
|
+
callbacks: options.callbacks
|
|
1347
|
+
});
|
|
1348
|
+
if (!isSigedWithAttestedKey) {
|
|
1349
|
+
throw new Openid4vciError(
|
|
1350
|
+
`Credential request jwt proof is not signed with a key in the 'key_attestation' jwt payload 'attested_keys'`
|
|
1351
|
+
);
|
|
1352
|
+
}
|
|
1353
|
+
}
|
|
1354
|
+
return jwt;
|
|
1355
|
+
}
|
|
1356
|
+
async function verifyCredentialRequestJwtProof(options) {
|
|
1357
|
+
const { header, payload } = (0, import_oauth213.decodeJwt)({
|
|
1358
|
+
jwt: options.jwt,
|
|
1359
|
+
headerSchema: zCredentialRequestJwtProofTypeHeader,
|
|
1360
|
+
payloadSchema: zCredentialRequestJwtProofTypePayload
|
|
1361
|
+
});
|
|
1362
|
+
const now = options.now?.getTime() ?? Date.now();
|
|
1363
|
+
if (options.nonceExpiresAt && now > options.nonceExpiresAt.getTime()) {
|
|
1364
|
+
throw new Openid4vciError("Nonce used for credential request proof expired");
|
|
1365
|
+
}
|
|
1366
|
+
const { signer } = await (0, import_oauth214.verifyJwt)({
|
|
1367
|
+
compact: options.jwt,
|
|
1368
|
+
header,
|
|
1369
|
+
payload,
|
|
1370
|
+
signer: (0, import_oauth214.jwtSignerFromJwt)({ header, payload }),
|
|
1371
|
+
verifyJwtCallback: options.callbacks.verifyJwt,
|
|
1372
|
+
errorMessage: "Error verifiying credential request proof jwt",
|
|
1373
|
+
expectedNonce: options.expectedNonce,
|
|
1374
|
+
expectedAudience: options.credentialIssuer,
|
|
1375
|
+
expectedIssuer: options.clientId,
|
|
1376
|
+
now: options.now
|
|
1377
|
+
});
|
|
1378
|
+
let keyAttestationResult = void 0;
|
|
1379
|
+
if (header.key_attestation) {
|
|
1380
|
+
keyAttestationResult = await verifyKeyAttestationJwt({
|
|
1381
|
+
callbacks: options.callbacks,
|
|
1382
|
+
keyAttestationJwt: header.key_attestation,
|
|
1383
|
+
use: "proof_type.jwt"
|
|
1384
|
+
});
|
|
1385
|
+
const isSigedWithAttestedKey = await (0, import_oauth213.isJwkInSet)({
|
|
1386
|
+
jwk: signer.publicJwk,
|
|
1387
|
+
jwks: keyAttestationResult.payload.attested_keys,
|
|
1388
|
+
callbacks: options.callbacks
|
|
1389
|
+
});
|
|
1390
|
+
if (!isSigedWithAttestedKey) {
|
|
1391
|
+
throw new Openid4vciError(
|
|
1392
|
+
`Credential request jwt proof is not signed with a key in the 'key_attestation' jwt payload 'attested_keys'`
|
|
1393
|
+
);
|
|
1394
|
+
}
|
|
1395
|
+
}
|
|
1396
|
+
return {
|
|
1397
|
+
header,
|
|
1398
|
+
payload,
|
|
1399
|
+
signer,
|
|
1400
|
+
keyAttestation: keyAttestationResult
|
|
1401
|
+
};
|
|
1402
|
+
}
|
|
1403
|
+
|
|
1404
|
+
// src/metadata/fetch-issuer-metadata.ts
|
|
1405
|
+
var import_oauth215 = require("@openid4vc/oauth2");
|
|
1406
|
+
var import_utils12 = require("@openid4vc/utils");
|
|
1407
|
+
async function resolveIssuerMetadata(credentialIssuer, options) {
|
|
1408
|
+
const allowAuthorizationMetadataFromCredentialIssuerMetadata = options?.allowAuthorizationMetadataFromCredentialIssuerMetadata ?? true;
|
|
1409
|
+
const credentialIssuerMetadataWithDraftVersion = await fetchCredentialIssuerMetadata(credentialIssuer, options?.fetch);
|
|
1410
|
+
if (!credentialIssuerMetadataWithDraftVersion) {
|
|
1411
|
+
throw new import_oauth215.Oauth2Error(`Well known credential issuer metadata for issuer '${credentialIssuer}' not found.`);
|
|
1412
|
+
}
|
|
1413
|
+
const { credentialIssuerMetadata, originalDraftVersion } = credentialIssuerMetadataWithDraftVersion;
|
|
1414
|
+
const authorizationServers = credentialIssuerMetadata.authorization_servers ?? [credentialIssuer];
|
|
1415
|
+
const authoriationServersMetadata = [];
|
|
1416
|
+
for (const authorizationServer of authorizationServers) {
|
|
1417
|
+
if (options?.restrictToAuthorizationServers && !options.restrictToAuthorizationServers.includes(authorizationServer)) {
|
|
1418
|
+
continue;
|
|
1419
|
+
}
|
|
1420
|
+
let authorizationServerMetadata = await (0, import_oauth215.fetchAuthorizationServerMetadata)(authorizationServer, options?.fetch);
|
|
1421
|
+
if (!authorizationServerMetadata && authorizationServer === credentialIssuer && allowAuthorizationMetadataFromCredentialIssuerMetadata) {
|
|
1422
|
+
authorizationServerMetadata = (0, import_utils12.parseWithErrorHandling)(
|
|
1423
|
+
import_oauth215.zAuthorizationServerMetadata,
|
|
1424
|
+
{
|
|
1425
|
+
token_endpoint: credentialIssuerMetadata.token_endpoint,
|
|
1426
|
+
issuer: credentialIssuer
|
|
1427
|
+
},
|
|
1428
|
+
`Well known authorization server metadata for authorization server '${authorizationServer}' not found, and could also not extract required values from the credential issuer metadata as a fallback.`
|
|
1429
|
+
);
|
|
1430
|
+
}
|
|
1431
|
+
if (!authorizationServerMetadata) {
|
|
1432
|
+
throw new import_oauth215.Oauth2Error(
|
|
1433
|
+
`Well known openid configuration or authorization server metadata for authorization server '${authorizationServer}' not found.`
|
|
1434
|
+
);
|
|
1435
|
+
}
|
|
1436
|
+
authoriationServersMetadata.push(authorizationServerMetadata);
|
|
1437
|
+
}
|
|
1438
|
+
return {
|
|
1439
|
+
originalDraftVersion,
|
|
1440
|
+
credentialIssuer: credentialIssuerMetadata,
|
|
1441
|
+
authorizationServers: authoriationServersMetadata
|
|
1442
|
+
};
|
|
1443
|
+
}
|
|
1444
|
+
|
|
1445
|
+
// src/nonce/nonce-request.ts
|
|
1446
|
+
var import_oauth216 = require("@openid4vc/oauth2");
|
|
1447
|
+
var import_utils14 = require("@openid4vc/utils");
|
|
1448
|
+
|
|
1449
|
+
// src/nonce/z-nonce.ts
|
|
1450
|
+
var import_utils13 = require("@openid4vc/utils");
|
|
1451
|
+
var import_zod18 = __toESM(require("zod"));
|
|
1452
|
+
var zNonceResponse = import_zod18.default.object({
|
|
1453
|
+
c_nonce: import_zod18.default.string(),
|
|
1454
|
+
c_nonce_expires_in: import_zod18.default.optional(import_utils13.zInteger)
|
|
1455
|
+
}).passthrough();
|
|
1456
|
+
|
|
1457
|
+
// src/nonce/nonce-request.ts
|
|
1458
|
+
async function requestNonce(options) {
|
|
1459
|
+
const fetchWithZod = (0, import_utils14.createZodFetcher)(options?.fetch);
|
|
1460
|
+
const nonceEndpoint = options.issuerMetadata.credentialIssuer.nonce_endpoint;
|
|
1461
|
+
if (!nonceEndpoint) {
|
|
1462
|
+
throw new Openid4vciError(
|
|
1463
|
+
`Credential issuer '${options.issuerMetadata.credentialIssuer.credential_issuer}' does not have a nonce endpoint.`
|
|
1464
|
+
);
|
|
1465
|
+
}
|
|
1466
|
+
const { response, result } = await fetchWithZod(zNonceResponse, import_utils14.ContentType.Json, nonceEndpoint, {
|
|
1467
|
+
method: "POST"
|
|
1468
|
+
});
|
|
1469
|
+
if (!response.ok || !result) {
|
|
1470
|
+
throw new import_oauth216.InvalidFetchResponseError(
|
|
1471
|
+
`Requesting nonce from '${nonceEndpoint}' resulted in an unsuccesfull response with status '${response.status}'`,
|
|
1472
|
+
await response.clone().text(),
|
|
1473
|
+
response
|
|
1474
|
+
);
|
|
1475
|
+
}
|
|
1476
|
+
if (!result.success) {
|
|
1477
|
+
throw new import_utils14.ValidationError("Error parsing nonce response", result.error);
|
|
1478
|
+
}
|
|
1479
|
+
return result.data;
|
|
1480
|
+
}
|
|
1481
|
+
function createNonceResponse(options) {
|
|
1482
|
+
return (0, import_utils14.parseWithErrorHandling)(zNonceResponse, {
|
|
1483
|
+
c_nonce: options.cNonce,
|
|
1484
|
+
c_nonce_expires_in: options.cNonceExpiresIn,
|
|
1485
|
+
...options.additionalPayload
|
|
1486
|
+
});
|
|
1487
|
+
}
|
|
1488
|
+
|
|
1489
|
+
// src/notification/notification.ts
|
|
1490
|
+
var import_oauth217 = require("@openid4vc/oauth2");
|
|
1491
|
+
var import_utils15 = require("@openid4vc/utils");
|
|
1492
|
+
|
|
1493
|
+
// src/notification/z-notification.ts
|
|
1494
|
+
var import_zod19 = __toESM(require("zod"));
|
|
1495
|
+
var zNotificationEvent = import_zod19.default.enum(["credential_accepted", "credential_failure", "credential_deleted"]);
|
|
1496
|
+
var zNotificationRequest = import_zod19.default.object({
|
|
1497
|
+
notification_id: import_zod19.default.string(),
|
|
1498
|
+
event: zNotificationEvent,
|
|
1499
|
+
event_description: import_zod19.default.optional(import_zod19.default.string())
|
|
1500
|
+
}).passthrough();
|
|
1501
|
+
var zNotificationErrorResponse = import_zod19.default.object({
|
|
1502
|
+
error: import_zod19.default.enum(["invalid_notification_id", "invalid_notification_request"])
|
|
1503
|
+
}).passthrough();
|
|
1504
|
+
|
|
1505
|
+
// src/notification/notification.ts
|
|
1506
|
+
async function sendNotifcation(options) {
|
|
1507
|
+
const notificationEndpoint = options.issuerMetadata.credentialIssuer.notification_endpoint;
|
|
1508
|
+
if (!notificationEndpoint) {
|
|
1509
|
+
throw new import_oauth217.Oauth2Error(
|
|
1510
|
+
`Credential issuer '${options.issuerMetadata.credentialIssuer.credential_issuer}' does not have a notification endpiont configured.`
|
|
1511
|
+
);
|
|
1512
|
+
}
|
|
1513
|
+
const notificationRequest = (0, import_utils15.parseWithErrorHandling)(
|
|
1514
|
+
zNotificationRequest,
|
|
1515
|
+
{
|
|
1516
|
+
event: options.notification.event,
|
|
1517
|
+
notification_id: options.notification.notificationId,
|
|
1518
|
+
event_description: options.notification.eventDescription
|
|
1519
|
+
},
|
|
1520
|
+
"Error validating notification request"
|
|
1521
|
+
);
|
|
1522
|
+
const resourceResponse = await (0, import_oauth217.resourceRequest)({
|
|
1523
|
+
dpop: options.dpop,
|
|
1524
|
+
accessToken: options.accessToken,
|
|
1525
|
+
callbacks: options.callbacks,
|
|
1526
|
+
url: notificationEndpoint,
|
|
1527
|
+
requestOptions: {
|
|
1528
|
+
method: "POST",
|
|
1529
|
+
headers: {
|
|
1530
|
+
"Content-Type": import_utils15.ContentType.Json
|
|
1531
|
+
},
|
|
1532
|
+
body: JSON.stringify(notificationRequest)
|
|
1533
|
+
}
|
|
1534
|
+
});
|
|
1535
|
+
if (!resourceResponse.ok) {
|
|
1536
|
+
const notificationErrorResponseResult = (0, import_utils15.isResponseContentType)(import_utils15.ContentType.Json, resourceResponse.response) ? zNotificationErrorResponse.safeParse(await resourceResponse.response.clone().json()) : void 0;
|
|
1537
|
+
return {
|
|
1538
|
+
...resourceResponse,
|
|
1539
|
+
notificationErrorResponseResult
|
|
1540
|
+
};
|
|
1541
|
+
}
|
|
1542
|
+
return resourceResponse;
|
|
1543
|
+
}
|
|
1544
|
+
|
|
1545
|
+
// src/Openid4vciClient.ts
|
|
1546
|
+
var AuthorizationFlow = /* @__PURE__ */ ((AuthorizationFlow2) => {
|
|
1547
|
+
AuthorizationFlow2["Oauth2Redirect"] = "Oauth2Redirect";
|
|
1548
|
+
AuthorizationFlow2["PresentationDuringIssuance"] = "PresentationDuringIssuance";
|
|
1549
|
+
return AuthorizationFlow2;
|
|
1550
|
+
})(AuthorizationFlow || {});
|
|
1551
|
+
var Openid4vciClient = class {
|
|
1552
|
+
constructor(options) {
|
|
1553
|
+
this.options = options;
|
|
1554
|
+
this.oauth2Client = new import_oauth218.Oauth2Client({
|
|
1555
|
+
callbacks: this.options.callbacks
|
|
1556
|
+
});
|
|
1557
|
+
}
|
|
1558
|
+
getKnownCredentialConfigurationsSupported(credentialIssuerMetadata) {
|
|
1559
|
+
return extractKnownCredentialConfigurationSupportedFormats(
|
|
1560
|
+
credentialIssuerMetadata.credential_configurations_supported
|
|
1561
|
+
);
|
|
1562
|
+
}
|
|
1563
|
+
/**
|
|
1564
|
+
* Resolve a credential offer into a credential offer object, handling both
|
|
1565
|
+
* 'credential_offer' and 'credential_offer_uri' params.
|
|
1566
|
+
*/
|
|
1567
|
+
async resolveCredentialOffer(credentialOffer) {
|
|
1568
|
+
return resolveCredentialOffer(credentialOffer, {
|
|
1569
|
+
fetch: this.options.callbacks.fetch
|
|
1570
|
+
});
|
|
1571
|
+
}
|
|
1572
|
+
async resolveIssuerMetadata(credentialIssuer) {
|
|
1573
|
+
return resolveIssuerMetadata(credentialIssuer, {
|
|
1574
|
+
fetch: this.options.callbacks.fetch
|
|
1575
|
+
});
|
|
1576
|
+
}
|
|
1577
|
+
/**
|
|
1578
|
+
* Retrieve an authorization code for a presentation during issuance session
|
|
1579
|
+
*
|
|
1580
|
+
* This can only be called if an authorization challenge was performed before and returned a
|
|
1581
|
+
* `presentation` paramater along with an `auth_session`. If the presentation response included
|
|
1582
|
+
* an `presentation_during_issuance_session` parameter it MUST be included in this request as well.
|
|
1583
|
+
*/
|
|
1584
|
+
async retrieveAuthorizationCodeUsingPresentation(options) {
|
|
1585
|
+
if (!options.credentialOffer.grants?.[import_oauth218.authorizationCodeGrantIdentifier]) {
|
|
1586
|
+
throw new import_oauth218.Oauth2Error(`Provided credential offer does not include the 'authorization_code' grant.`);
|
|
1587
|
+
}
|
|
1588
|
+
const authorizationCodeGrant = options.credentialOffer.grants[import_oauth218.authorizationCodeGrantIdentifier];
|
|
1589
|
+
const authorizationServer = determineAuthorizationServerForCredentialOffer({
|
|
1590
|
+
issuerMetadata: options.issuerMetadata,
|
|
1591
|
+
grantAuthorizationServer: authorizationCodeGrant.authorization_server
|
|
1592
|
+
});
|
|
1593
|
+
const authorizationServerMetadata = (0, import_oauth218.getAuthorizationServerMetadataFromList)(
|
|
1594
|
+
options.issuerMetadata.authorizationServers,
|
|
1595
|
+
authorizationServer
|
|
1596
|
+
);
|
|
1597
|
+
const oauth2Client = new import_oauth218.Oauth2Client({ callbacks: this.options.callbacks });
|
|
1598
|
+
const { authorizationChallengeResponse, dpop } = await oauth2Client.sendAuthorizationChallengeRequest({
|
|
1599
|
+
authorizationServerMetadata,
|
|
1600
|
+
authSession: options.authSession,
|
|
1601
|
+
presentationDuringIssuanceSession: options.presentationDuringIssuanceSession,
|
|
1602
|
+
dpop: options.dpop
|
|
1603
|
+
});
|
|
1604
|
+
return { authorizationChallengeResponse, dpop };
|
|
1605
|
+
}
|
|
1606
|
+
/**
|
|
1607
|
+
* Initiates authorization for credential issuance. It handles the following cases:
|
|
1608
|
+
* - Authorization Challenge
|
|
1609
|
+
* - Pushed Authorization Request
|
|
1610
|
+
* - Regular Authorization url
|
|
1611
|
+
*
|
|
1612
|
+
* In case the authorization challenge request returns an error with `insufficient_authorization`
|
|
1613
|
+
* with a `presentation` field it means the authorization server expects presentation of credentials
|
|
1614
|
+
* before issuance of crednetials. If this is the case, the value in `presentation` should be treated
|
|
1615
|
+
* as an openid4vp authorization request and submitted to the verifier. Once the presentation response
|
|
1616
|
+
* has been submitted, the RP will respnosd with a `presentation_during_issuance_session` parameter.
|
|
1617
|
+
* Together with the `auth_session` parameter returned in this call you can retrieve an `authorization_code`
|
|
1618
|
+
* using
|
|
1619
|
+
*/
|
|
1620
|
+
async initiateAuthorization(options) {
|
|
1621
|
+
if (!options.credentialOffer.grants?.[import_oauth218.authorizationCodeGrantIdentifier]) {
|
|
1622
|
+
throw new import_oauth218.Oauth2Error(`Provided credential offer does not include the 'authorization_code' grant.`);
|
|
1623
|
+
}
|
|
1624
|
+
const authorizationCodeGrant = options.credentialOffer.grants[import_oauth218.authorizationCodeGrantIdentifier];
|
|
1625
|
+
const authorizationServer = determineAuthorizationServerForCredentialOffer({
|
|
1626
|
+
issuerMetadata: options.issuerMetadata,
|
|
1627
|
+
grantAuthorizationServer: authorizationCodeGrant.authorization_server
|
|
1628
|
+
});
|
|
1629
|
+
const authorizationServerMetadata = (0, import_oauth218.getAuthorizationServerMetadataFromList)(
|
|
1630
|
+
options.issuerMetadata.authorizationServers,
|
|
1631
|
+
authorizationServer
|
|
1632
|
+
);
|
|
1633
|
+
const oauth2Client = new import_oauth218.Oauth2Client({ callbacks: this.options.callbacks });
|
|
1634
|
+
try {
|
|
1635
|
+
const result = await oauth2Client.initiateAuthorization({
|
|
1636
|
+
clientId: options.clientId,
|
|
1637
|
+
pkceCodeVerifier: options.pkceCodeVerifier,
|
|
1638
|
+
redirectUri: options.redirectUri,
|
|
1639
|
+
scope: options.scope,
|
|
1640
|
+
additionalRequestPayload: {
|
|
1641
|
+
...options.additionalRequestPayload,
|
|
1642
|
+
issuer_state: options.credentialOffer?.grants?.authorization_code?.issuer_state
|
|
1643
|
+
},
|
|
1644
|
+
dpop: options.dpop,
|
|
1645
|
+
clientAttestation: options.clientAttestation,
|
|
1646
|
+
resource: options.issuerMetadata.credentialIssuer.credential_issuer,
|
|
1647
|
+
authorizationServerMetadata
|
|
1648
|
+
});
|
|
1649
|
+
return {
|
|
1650
|
+
...result,
|
|
1651
|
+
authorizationFlow: "Oauth2Redirect" /* Oauth2Redirect */,
|
|
1652
|
+
authorizationServer: authorizationServerMetadata.issuer
|
|
1653
|
+
};
|
|
1654
|
+
} catch (error) {
|
|
1655
|
+
if (error instanceof import_oauth218.Oauth2ClientAuthorizationChallengeError && error.errorResponse.error === import_oauth218.Oauth2ErrorCodes.InsufficientAuthorization && error.errorResponse.presentation) {
|
|
1656
|
+
if (!error.errorResponse.auth_session) {
|
|
1657
|
+
throw new Openid4vciError(
|
|
1658
|
+
`Expected 'auth_session' to be defined with authorization challenge response error '${error.errorResponse.error}' and 'presentation' parameter`
|
|
1659
|
+
);
|
|
1660
|
+
}
|
|
1661
|
+
return {
|
|
1662
|
+
authorizationFlow: "PresentationDuringIssuance" /* PresentationDuringIssuance */,
|
|
1663
|
+
openid4vpRequestUrl: error.errorResponse.presentation,
|
|
1664
|
+
authSession: error.errorResponse.auth_session,
|
|
1665
|
+
authorizationServer: authorizationServerMetadata.issuer
|
|
1666
|
+
};
|
|
1667
|
+
}
|
|
1668
|
+
throw error;
|
|
1669
|
+
}
|
|
1670
|
+
}
|
|
1671
|
+
/**
|
|
1672
|
+
* Convenience method around {@link Oauth2Client.createAuthorizationRequestUrl}
|
|
1673
|
+
* but specifically focused on a credential offer
|
|
1674
|
+
*/
|
|
1675
|
+
async createAuthorizationRequestUrlFromOffer(options) {
|
|
1676
|
+
if (!options.credentialOffer.grants?.[import_oauth218.authorizationCodeGrantIdentifier]) {
|
|
1677
|
+
throw new import_oauth218.Oauth2Error(`Provided credential offer does not include the 'authorization_code' grant.`);
|
|
1678
|
+
}
|
|
1679
|
+
const authorizationCodeGrant = options.credentialOffer.grants[import_oauth218.authorizationCodeGrantIdentifier];
|
|
1680
|
+
const authorizationServer = determineAuthorizationServerForCredentialOffer({
|
|
1681
|
+
issuerMetadata: options.issuerMetadata,
|
|
1682
|
+
grantAuthorizationServer: authorizationCodeGrant.authorization_server
|
|
1683
|
+
});
|
|
1684
|
+
const authorizationServerMetadata = (0, import_oauth218.getAuthorizationServerMetadataFromList)(
|
|
1685
|
+
options.issuerMetadata.authorizationServers,
|
|
1686
|
+
authorizationServer
|
|
1687
|
+
);
|
|
1688
|
+
const { authorizationRequestUrl, pkce, dpop } = await this.oauth2Client.createAuthorizationRequestUrl({
|
|
1689
|
+
authorizationServerMetadata,
|
|
1690
|
+
clientId: options.clientId,
|
|
1691
|
+
additionalRequestPayload: {
|
|
1692
|
+
...options.additionalRequestPayload,
|
|
1693
|
+
issuer_state: options.credentialOffer?.grants?.authorization_code?.issuer_state
|
|
1694
|
+
},
|
|
1695
|
+
resource: options.issuerMetadata.credentialIssuer.credential_issuer,
|
|
1696
|
+
redirectUri: options.redirectUri,
|
|
1697
|
+
scope: options.scope,
|
|
1698
|
+
pkceCodeVerifier: options.pkceCodeVerifier,
|
|
1699
|
+
clientAttestation: options.clientAttestation,
|
|
1700
|
+
dpop: options.dpop
|
|
1701
|
+
});
|
|
1702
|
+
return {
|
|
1703
|
+
authorizationRequestUrl,
|
|
1704
|
+
pkce,
|
|
1705
|
+
dpop,
|
|
1706
|
+
authorizationServer: authorizationServerMetadata.issuer
|
|
1707
|
+
};
|
|
1708
|
+
}
|
|
1709
|
+
/**
|
|
1710
|
+
* Convenience method around {@link Oauth2Client.retrievePreAuthorizedCodeAccessToken}
|
|
1711
|
+
* but specifically focused on a credential offer
|
|
1712
|
+
*/
|
|
1713
|
+
async retrievePreAuthorizedCodeAccessTokenFromOffer({
|
|
1714
|
+
credentialOffer,
|
|
1715
|
+
issuerMetadata,
|
|
1716
|
+
additionalRequestPayload,
|
|
1717
|
+
txCode,
|
|
1718
|
+
dpop,
|
|
1719
|
+
clientAttestation
|
|
1720
|
+
}) {
|
|
1721
|
+
if (!credentialOffer.grants?.[import_oauth218.preAuthorizedCodeGrantIdentifier]) {
|
|
1722
|
+
throw new import_oauth218.Oauth2Error(`The credential offer does not contain the '${import_oauth218.preAuthorizedCodeGrantIdentifier}' grant.`);
|
|
1723
|
+
}
|
|
1724
|
+
if (credentialOffer.grants[import_oauth218.preAuthorizedCodeGrantIdentifier].tx_code && !txCode) {
|
|
1725
|
+
throw new import_oauth218.Oauth2Error(
|
|
1726
|
+
`Retrieving access token requires a 'tx_code' in the request, but the 'txCode' parameter was not provided.`
|
|
1727
|
+
);
|
|
1728
|
+
}
|
|
1729
|
+
const preAuthorizedCode = credentialOffer.grants[import_oauth218.preAuthorizedCodeGrantIdentifier]["pre-authorized_code"];
|
|
1730
|
+
const authorizationServer = determineAuthorizationServerForCredentialOffer({
|
|
1731
|
+
grantAuthorizationServer: credentialOffer.grants[import_oauth218.preAuthorizedCodeGrantIdentifier].authorization_server,
|
|
1732
|
+
issuerMetadata
|
|
1733
|
+
});
|
|
1734
|
+
const authorizationServerMetadata = (0, import_oauth218.getAuthorizationServerMetadataFromList)(
|
|
1735
|
+
issuerMetadata.authorizationServers,
|
|
1736
|
+
authorizationServer
|
|
1737
|
+
);
|
|
1738
|
+
const result = await this.oauth2Client.retrievePreAuthorizedCodeAccessToken({
|
|
1739
|
+
authorizationServerMetadata,
|
|
1740
|
+
preAuthorizedCode,
|
|
1741
|
+
txCode,
|
|
1742
|
+
resource: issuerMetadata.credentialIssuer.credential_issuer,
|
|
1743
|
+
additionalRequestPayload,
|
|
1744
|
+
dpop,
|
|
1745
|
+
clientAttestation
|
|
1746
|
+
});
|
|
1747
|
+
return {
|
|
1748
|
+
...result,
|
|
1749
|
+
authorizationServer
|
|
1750
|
+
};
|
|
1751
|
+
}
|
|
1752
|
+
/**
|
|
1753
|
+
* Convenience method around {@link Oauth2Client.retrieveAuthorizationCodeAccessTokenFrom}
|
|
1754
|
+
* but specifically focused on a credential offer
|
|
1755
|
+
*/
|
|
1756
|
+
async retrieveAuthorizationCodeAccessTokenFromOffer({
|
|
1757
|
+
issuerMetadata,
|
|
1758
|
+
additionalRequestPayload,
|
|
1759
|
+
credentialOffer,
|
|
1760
|
+
authorizationCode,
|
|
1761
|
+
pkceCodeVerifier,
|
|
1762
|
+
redirectUri,
|
|
1763
|
+
dpop,
|
|
1764
|
+
clientAttestation
|
|
1765
|
+
}) {
|
|
1766
|
+
if (!credentialOffer.grants?.[import_oauth218.authorizationCodeGrantIdentifier]) {
|
|
1767
|
+
throw new import_oauth218.Oauth2Error(`The credential offer does not contain the '${import_oauth218.authorizationCodeGrantIdentifier}' grant.`);
|
|
1768
|
+
}
|
|
1769
|
+
const authorizationServer = determineAuthorizationServerForCredentialOffer({
|
|
1770
|
+
grantAuthorizationServer: credentialOffer.grants[import_oauth218.authorizationCodeGrantIdentifier].authorization_server,
|
|
1771
|
+
issuerMetadata
|
|
1772
|
+
});
|
|
1773
|
+
const authorizationServerMetadata = (0, import_oauth218.getAuthorizationServerMetadataFromList)(
|
|
1774
|
+
issuerMetadata.authorizationServers,
|
|
1775
|
+
authorizationServer
|
|
1776
|
+
);
|
|
1777
|
+
const result = await this.oauth2Client.retrieveAuthorizationCodeAccessToken({
|
|
1778
|
+
authorizationServerMetadata,
|
|
1779
|
+
authorizationCode,
|
|
1780
|
+
pkceCodeVerifier,
|
|
1781
|
+
additionalRequestPayload,
|
|
1782
|
+
dpop,
|
|
1783
|
+
clientAttestation,
|
|
1784
|
+
redirectUri,
|
|
1785
|
+
resource: issuerMetadata.credentialIssuer.credential_issuer
|
|
1786
|
+
});
|
|
1787
|
+
return {
|
|
1788
|
+
...result,
|
|
1789
|
+
authorizationServer
|
|
1790
|
+
};
|
|
1791
|
+
}
|
|
1792
|
+
/**
|
|
1793
|
+
* Request a nonce to be used in credential request proofs from the `nonce_endpoint`
|
|
1794
|
+
*
|
|
1795
|
+
* @throws Openid4vciError - if no `nonce_endpoint` is configured in the issuer metadata
|
|
1796
|
+
* @thrwos InvalidFetchResponseError - if the nonce endpoint did not return a succesfull response
|
|
1797
|
+
* @throws ValidationError - if validating the nonce response failed
|
|
1798
|
+
*/
|
|
1799
|
+
async requestNonce(options) {
|
|
1800
|
+
return requestNonce(options);
|
|
1801
|
+
}
|
|
1802
|
+
/**
|
|
1803
|
+
* Creates the jwt proof payload and header to be included in a credential request.
|
|
1804
|
+
*/
|
|
1805
|
+
async createCredentialRequestJwtProof(options) {
|
|
1806
|
+
const credentialConfiguration = options.issuerMetadata.credentialIssuer.credential_configurations_supported[options.credentialConfigurationId];
|
|
1807
|
+
if (!credentialConfiguration) {
|
|
1808
|
+
throw new Openid4vciError(
|
|
1809
|
+
`Credential configuration with '${options.credentialConfigurationId}' not found in 'credential_configurations_supported' from credential issuer '${options.issuerMetadata.credentialIssuer.credential_issuer}'`
|
|
1810
|
+
);
|
|
1811
|
+
}
|
|
1812
|
+
if (credentialConfiguration.proof_types_supported) {
|
|
1813
|
+
if (!credentialConfiguration.proof_types_supported.jwt) {
|
|
1814
|
+
throw new Openid4vciError(
|
|
1815
|
+
`Credential configuration with id '${options.credentialConfigurationId}' does not support the 'jwt' proof type.`
|
|
1816
|
+
);
|
|
1817
|
+
}
|
|
1818
|
+
if (!credentialConfiguration.proof_types_supported.jwt.proof_signing_alg_values_supported.includes(
|
|
1819
|
+
options.signer.alg
|
|
1820
|
+
)) {
|
|
1821
|
+
throw new Openid4vciError(
|
|
1822
|
+
`Credential configuration with id '${options.credentialConfigurationId}' does not support the '${options.signer.alg}' alg for 'jwt' proof type.`
|
|
1823
|
+
);
|
|
1824
|
+
}
|
|
1825
|
+
if (credentialConfiguration.proof_types_supported.jwt.key_attestations_required && !options.keyAttestationJwt) {
|
|
1826
|
+
throw new Openid4vciError(
|
|
1827
|
+
`Credential configuration with id '${options.credentialConfigurationId}' requires key attestations for 'jwt' proof type but no 'keyAttestationJwt' was provided`
|
|
1828
|
+
);
|
|
1829
|
+
}
|
|
1830
|
+
}
|
|
1831
|
+
const jwt = await createCredentialRequestJwtProof({
|
|
1832
|
+
credentialIssuer: options.issuerMetadata.credentialIssuer.credential_issuer,
|
|
1833
|
+
signer: options.signer,
|
|
1834
|
+
clientId: options.clientId,
|
|
1835
|
+
issuedAt: options.issuedAt,
|
|
1836
|
+
nonce: options.nonce,
|
|
1837
|
+
keyAttestationJwt: options.keyAttestationJwt,
|
|
1838
|
+
callbacks: this.options.callbacks
|
|
1839
|
+
});
|
|
1840
|
+
return {
|
|
1841
|
+
jwt
|
|
1842
|
+
};
|
|
1843
|
+
}
|
|
1844
|
+
/**
|
|
1845
|
+
* @throws Openid4vciRetrieveCredentialsError - if an unsuccesfull response or the respnose couldn't be parsed as credential response
|
|
1846
|
+
* @throws ValidationError - if validation of the credential request failed
|
|
1847
|
+
* @throws Openid4vciError - if the `credentialConfigurationId` couldn't be found, or if the the format specific request couldn't be constructed
|
|
1848
|
+
*/
|
|
1849
|
+
async retrieveCredentials({
|
|
1850
|
+
issuerMetadata,
|
|
1851
|
+
proof,
|
|
1852
|
+
proofs,
|
|
1853
|
+
credentialConfigurationId,
|
|
1854
|
+
additionalRequestPayload,
|
|
1855
|
+
accessToken,
|
|
1856
|
+
dpop
|
|
1857
|
+
}) {
|
|
1858
|
+
const formatPayload = getCredentialRequestFormatPayloadForCredentialConfigurationId({
|
|
1859
|
+
credentialConfigurationId,
|
|
1860
|
+
issuerMetadata
|
|
1861
|
+
});
|
|
1862
|
+
const credentialResponse = await retrieveCredentialsWithFormat({
|
|
1863
|
+
accessToken,
|
|
1864
|
+
formatPayload,
|
|
1865
|
+
issuerMetadata,
|
|
1866
|
+
additionalRequestPayload,
|
|
1867
|
+
proof,
|
|
1868
|
+
proofs,
|
|
1869
|
+
callbacks: this.options.callbacks,
|
|
1870
|
+
dpop
|
|
1871
|
+
});
|
|
1872
|
+
if (!credentialResponse.ok) {
|
|
1873
|
+
throw new Openid4vciRetrieveCredentialsError(
|
|
1874
|
+
`Error retrieving credentials from '${issuerMetadata.credentialIssuer.credential_issuer}'`,
|
|
1875
|
+
credentialResponse,
|
|
1876
|
+
await credentialResponse.response.clone().text()
|
|
1877
|
+
);
|
|
1878
|
+
}
|
|
1879
|
+
return credentialResponse;
|
|
1880
|
+
}
|
|
1881
|
+
/**
|
|
1882
|
+
* @throws Openid4vciSendNotificationError - if an unsuccesfull response
|
|
1883
|
+
* @throws ValidationError - if validation of the notification request failed
|
|
1884
|
+
*/
|
|
1885
|
+
async sendNotification({
|
|
1886
|
+
issuerMetadata,
|
|
1887
|
+
notification,
|
|
1888
|
+
additionalRequestPayload,
|
|
1889
|
+
accessToken,
|
|
1890
|
+
dpop
|
|
1891
|
+
}) {
|
|
1892
|
+
const notificationResponse = await sendNotifcation({
|
|
1893
|
+
accessToken,
|
|
1894
|
+
issuerMetadata,
|
|
1895
|
+
additionalRequestPayload,
|
|
1896
|
+
callbacks: this.options.callbacks,
|
|
1897
|
+
dpop,
|
|
1898
|
+
notification
|
|
1899
|
+
});
|
|
1900
|
+
if (!notificationResponse.ok) {
|
|
1901
|
+
throw new Openid4vciSendNotificationError(
|
|
1902
|
+
`Error sending notification to '${issuerMetadata.credentialIssuer.credential_issuer}'`,
|
|
1903
|
+
notificationResponse
|
|
1904
|
+
);
|
|
1905
|
+
}
|
|
1906
|
+
return notificationResponse;
|
|
1907
|
+
}
|
|
1908
|
+
};
|
|
1909
|
+
|
|
1910
|
+
// src/Openid4vciIssuer.ts
|
|
1911
|
+
var import_oauth219 = require("@openid4vc/oauth2");
|
|
1912
|
+
var import_utils18 = require("@openid4vc/utils");
|
|
1913
|
+
|
|
1914
|
+
// src/credential-request/credential-response.ts
|
|
1915
|
+
var import_utils16 = require("@openid4vc/utils");
|
|
1916
|
+
function createCredentialResponse(options) {
|
|
1917
|
+
const credentialResponse = (0, import_utils16.parseWithErrorHandling)(zCredentialResponse, {
|
|
1918
|
+
c_nonce: options.cNonce,
|
|
1919
|
+
c_nonce_expires_in: options.cNonceExpiresInSeconds,
|
|
1920
|
+
credential: options.credential,
|
|
1921
|
+
credentials: options.credentials,
|
|
1922
|
+
notification_id: options.notificationId,
|
|
1923
|
+
// NOTE `format` is removed in draft 13. For now if a format was requested
|
|
1924
|
+
// we just always return it in the response as well.
|
|
1925
|
+
format: options.credentialRequest.format?.format,
|
|
1926
|
+
...options.additionalPayload
|
|
1927
|
+
});
|
|
1928
|
+
return credentialResponse;
|
|
1929
|
+
}
|
|
1930
|
+
|
|
1931
|
+
// src/credential-request/parse-credential-request.ts
|
|
1932
|
+
var import_utils17 = require("@openid4vc/utils");
|
|
1933
|
+
var import_zod20 = __toESM(require("zod"));
|
|
1934
|
+
function parseCredentialRequest(options) {
|
|
1935
|
+
const credentialRequest = (0, import_utils17.parseWithErrorHandling)(
|
|
1936
|
+
zCredentialRequest,
|
|
1937
|
+
options.credentialRequest,
|
|
1938
|
+
"Error validating credential request"
|
|
1939
|
+
);
|
|
1940
|
+
let proofs = void 0;
|
|
1941
|
+
const knownProofs = zCredentialRequestProofs.strict().safeParse(credentialRequest.proofs);
|
|
1942
|
+
if (knownProofs.success) {
|
|
1943
|
+
proofs = knownProofs.data;
|
|
1944
|
+
}
|
|
1945
|
+
const knownProof = import_zod20.default.union(allCredentialRequestProofs).safeParse(credentialRequest.proof);
|
|
1946
|
+
if (knownProof.success && knownProof.data.proof_type === jwtProofTypeIdentifier) {
|
|
1947
|
+
proofs = { [jwtProofTypeIdentifier]: [knownProof.data.jwt] };
|
|
1948
|
+
} else if (knownProof.success && knownProof.data.proof_type === attestationProofTypeIdentifier) {
|
|
1949
|
+
proofs = { [attestationProofTypeIdentifier]: [knownProof.data.attestation] };
|
|
1950
|
+
}
|
|
1951
|
+
if (credentialRequest.credential_identifier) {
|
|
1952
|
+
return {
|
|
1953
|
+
credentialIdentifier: credentialRequest.credential_identifier,
|
|
1954
|
+
credentialRequest,
|
|
1955
|
+
proofs
|
|
1956
|
+
};
|
|
1957
|
+
}
|
|
1958
|
+
if (credentialRequest.format && allCredentialRequestFormatIdentifiers.includes(credentialRequest.format)) {
|
|
1959
|
+
return {
|
|
1960
|
+
// Removes all claims that are not specific to this format
|
|
1961
|
+
format: (0, import_utils17.parseWithErrorHandling)(
|
|
1962
|
+
import_zod20.default.union(allCredentialRequestFormats),
|
|
1963
|
+
credentialRequest,
|
|
1964
|
+
"Unable to validate format specific properties from credential request"
|
|
1965
|
+
),
|
|
1966
|
+
credentialRequest,
|
|
1967
|
+
proofs
|
|
1968
|
+
};
|
|
1969
|
+
}
|
|
1970
|
+
return {
|
|
1971
|
+
credentialRequest,
|
|
1972
|
+
proofs
|
|
1973
|
+
};
|
|
1974
|
+
}
|
|
1975
|
+
|
|
1976
|
+
// src/formats/proof-type/attestation/attestation-proof-type.ts
|
|
1977
|
+
async function verifyCredentialRequestAttestationProof(options) {
|
|
1978
|
+
const verificationResult = await verifyKeyAttestationJwt({
|
|
1979
|
+
...options,
|
|
1980
|
+
use: "proof_type.attestation"
|
|
1981
|
+
});
|
|
1982
|
+
return verificationResult;
|
|
1983
|
+
}
|
|
1984
|
+
|
|
1985
|
+
// src/Openid4vciIssuer.ts
|
|
1986
|
+
var Openid4vciIssuer = class {
|
|
1987
|
+
constructor(options) {
|
|
1988
|
+
this.options = options;
|
|
1989
|
+
}
|
|
1990
|
+
getCredentialIssuerMetadataDraft11(credentialIssuerMetadata) {
|
|
1991
|
+
return (0, import_utils18.parseWithErrorHandling)(zCredentialIssuerMetadataWithDraft11, credentialIssuerMetadata);
|
|
1992
|
+
}
|
|
1993
|
+
getKnownCredentialConfigurationsSupported(credentialIssuerMetadata) {
|
|
1994
|
+
return extractKnownCredentialConfigurationSupportedFormats(
|
|
1995
|
+
credentialIssuerMetadata.credential_configurations_supported
|
|
1996
|
+
);
|
|
1997
|
+
}
|
|
1998
|
+
/**
|
|
1999
|
+
* Create issuer metadata and validates the structure is correct
|
|
2000
|
+
*/
|
|
2001
|
+
createCredentialIssuerMetadata(credentialIssuerMetadata) {
|
|
2002
|
+
return (0, import_utils18.parseWithErrorHandling)(
|
|
2003
|
+
zCredentialIssuerMetadata,
|
|
2004
|
+
credentialIssuerMetadata,
|
|
2005
|
+
"Error validating credential issuer metadata"
|
|
2006
|
+
);
|
|
2007
|
+
}
|
|
2008
|
+
async createCredentialOffer(options) {
|
|
2009
|
+
return createCredentialOffer({
|
|
2010
|
+
callbacks: this.options.callbacks,
|
|
2011
|
+
credentialConfigurationIds: options.credentialConfigurationIds,
|
|
2012
|
+
grants: options.grants,
|
|
2013
|
+
issuerMetadata: options.issuerMetadata,
|
|
2014
|
+
additionalPayload: options.additionalPayload,
|
|
2015
|
+
credentialOfferScheme: options.credentialOfferScheme,
|
|
2016
|
+
credentialOfferUri: options.credentialOfferUri
|
|
2017
|
+
});
|
|
2018
|
+
}
|
|
2019
|
+
/**
|
|
2020
|
+
* @throws Oauth2ServerErrorResponseError - if verification of the jwt failed. You can extract
|
|
2021
|
+
* the credential error response from this.
|
|
2022
|
+
*/
|
|
2023
|
+
async verifyCredentialRequestJwtProof(options) {
|
|
2024
|
+
try {
|
|
2025
|
+
return await verifyCredentialRequestJwtProof({
|
|
2026
|
+
callbacks: this.options.callbacks,
|
|
2027
|
+
credentialIssuer: options.issuerMetadata.credentialIssuer.credential_issuer,
|
|
2028
|
+
expectedNonce: options.expectedNonce,
|
|
2029
|
+
nonceExpiresAt: options.nonceExpiresAt,
|
|
2030
|
+
jwt: options.jwt,
|
|
2031
|
+
clientId: options.clientId,
|
|
2032
|
+
now: options.now
|
|
2033
|
+
});
|
|
2034
|
+
} catch (error) {
|
|
2035
|
+
throw new import_oauth219.Oauth2ServerErrorResponseError(
|
|
2036
|
+
{
|
|
2037
|
+
error: import_oauth219.Oauth2ErrorCodes.InvalidProof,
|
|
2038
|
+
error_description: (
|
|
2039
|
+
// TOOD: error should have a internalErrorMessage and a publicErrorMessage
|
|
2040
|
+
error instanceof import_oauth219.Oauth2JwtVerificationError || error instanceof Openid4vciError ? error.message : "Invalid proof"
|
|
2041
|
+
)
|
|
2042
|
+
},
|
|
2043
|
+
{
|
|
2044
|
+
internalMessage: "Error verifying credential request proof jwt",
|
|
2045
|
+
cause: error
|
|
2046
|
+
}
|
|
2047
|
+
);
|
|
2048
|
+
}
|
|
2049
|
+
}
|
|
2050
|
+
/**
|
|
2051
|
+
* @throws Oauth2ServerErrorResponseError - if verification of the key attestation failed. You can extract
|
|
2052
|
+
* the credential error response from this.
|
|
2053
|
+
*/
|
|
2054
|
+
async verifyCredentialRequestAttestationProof(options) {
|
|
2055
|
+
try {
|
|
2056
|
+
return await verifyCredentialRequestAttestationProof({
|
|
2057
|
+
callbacks: this.options.callbacks,
|
|
2058
|
+
expectedNonce: options.expectedNonce,
|
|
2059
|
+
keyAttestationJwt: options.keyAttestationJwt,
|
|
2060
|
+
nonceExpiresAt: options.nonceExpiresAt,
|
|
2061
|
+
now: options.now
|
|
2062
|
+
});
|
|
2063
|
+
} catch (error) {
|
|
2064
|
+
throw new import_oauth219.Oauth2ServerErrorResponseError(
|
|
2065
|
+
{
|
|
2066
|
+
error: import_oauth219.Oauth2ErrorCodes.InvalidProof,
|
|
2067
|
+
error_description: (
|
|
2068
|
+
// TOOD: error should have a internalErrorMessage and a publicErrorMessage
|
|
2069
|
+
error instanceof import_oauth219.Oauth2JwtVerificationError || error instanceof Openid4vciError ? error.message : "Invalid proof"
|
|
2070
|
+
)
|
|
2071
|
+
},
|
|
2072
|
+
{
|
|
2073
|
+
internalMessage: "Error verifying credential request proof attestation",
|
|
2074
|
+
cause: error
|
|
2075
|
+
}
|
|
2076
|
+
);
|
|
2077
|
+
}
|
|
2078
|
+
}
|
|
2079
|
+
/**
|
|
2080
|
+
* @throws Oauth2ServerErrorResponseError - when validation of the credential request fails
|
|
2081
|
+
* You can extract the credential error response from this.
|
|
2082
|
+
*/
|
|
2083
|
+
parseCredentialRequest(options) {
|
|
2084
|
+
try {
|
|
2085
|
+
return parseCredentialRequest(options);
|
|
2086
|
+
} catch (error) {
|
|
2087
|
+
throw new import_oauth219.Oauth2ServerErrorResponseError(
|
|
2088
|
+
{
|
|
2089
|
+
error: import_oauth219.Oauth2ErrorCodes.InvalidCredentialRequest,
|
|
2090
|
+
error_description: (
|
|
2091
|
+
// TODO: error should have a internalErrorMessage and a publicErrorMessage
|
|
2092
|
+
error instanceof import_utils18.ValidationError ? error.message : "Invalid request"
|
|
2093
|
+
)
|
|
2094
|
+
},
|
|
2095
|
+
{
|
|
2096
|
+
internalMessage: "Error verifying credential request proof jwt",
|
|
2097
|
+
cause: error
|
|
2098
|
+
}
|
|
2099
|
+
);
|
|
2100
|
+
}
|
|
2101
|
+
}
|
|
2102
|
+
/**
|
|
2103
|
+
* @throws ValidationError - when validation of the credential response fails
|
|
2104
|
+
*/
|
|
2105
|
+
createCredentialResponse(options) {
|
|
2106
|
+
return createCredentialResponse(options);
|
|
2107
|
+
}
|
|
2108
|
+
/**
|
|
2109
|
+
* @throws ValidationError - when validation of the nonce response fails
|
|
2110
|
+
*/
|
|
2111
|
+
createNonceResponse(options) {
|
|
2112
|
+
return createNonceResponse(options);
|
|
2113
|
+
}
|
|
2114
|
+
};
|
|
2115
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
2116
|
+
0 && (module.exports = {
|
|
2117
|
+
AuthorizationFlow,
|
|
2118
|
+
Openid4vciClient,
|
|
2119
|
+
Openid4vciDraftVersion,
|
|
2120
|
+
Openid4vciError,
|
|
2121
|
+
Openid4vciIssuer,
|
|
2122
|
+
Openid4vciRetrieveCredentialsError,
|
|
2123
|
+
Openid4vciSendNotificationError,
|
|
2124
|
+
credentialsSupportedToCredentialConfigurationsSupported,
|
|
2125
|
+
extractScopesForCredentialConfigurationIds,
|
|
2126
|
+
getCredentialConfigurationsMatchingRequestFormat,
|
|
2127
|
+
getGlobalConfig,
|
|
2128
|
+
setGlobalConfig
|
|
2129
|
+
});
|
|
2130
|
+
//# sourceMappingURL=index.js.map
|