@openid4vc/openid4vp 0.3.0-alpha-20250320222745 → 0.3.0-alpha-20250321120839

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  // src/client-identifier-scheme/parse-client-identifier-scheme.ts
2
- import { Oauth2ErrorCodes as Oauth2ErrorCodes2, Oauth2ServerErrorResponseError as Oauth2ServerErrorResponseError2, getGlobalConfig } from "@openid4vc/oauth2";
3
- import { URL as URL2 } from "@openid4vc/utils";
2
+ import { Oauth2ErrorCodes, Oauth2ServerErrorResponseError } from "@openid4vc/oauth2";
3
+ import { URL as URL2, zHttpsUrl as zHttpsUrl3 } from "@openid4vc/utils";
4
4
 
5
5
  // src/authorization-request/z-authorization-request-dc-api.ts
6
6
  import { z as z5 } from "zod";
@@ -139,37 +139,31 @@ var zOpenid4vpAuthorizationRequestFromUriParams = z4.string().url().transform((u
139
139
  );
140
140
 
141
141
  // src/authorization-request/z-authorization-request-dc-api.ts
142
+ var zOpenid4vpResponseModeDcApi = z5.enum(["dc_api", "dc_api.jwt", "w3c_dc_api.jwt", "w3c_dc_api"]);
142
143
  var zOpenid4vpAuthorizationRequestDcApi = zOpenid4vpAuthorizationRequest.pick({
143
- client_id: true,
144
144
  response_type: true,
145
- response_mode: true,
146
145
  nonce: true,
147
146
  presentation_definition: true,
148
147
  client_metadata: true,
149
148
  transaction_data: true,
150
149
  dcql_query: true,
151
- trust_chain: true
150
+ trust_chain: true,
151
+ state: true
152
152
  }).extend({
153
153
  client_id: z5.optional(z5.string()),
154
154
  expected_origins: z5.array(z5.string()).optional(),
155
- response_mode: z5.enum(["dc_api", "dc_api.jwt", "w3c_dc_api.jwt", "w3c_dc_api"]),
156
- client_id_scheme: z5.enum([
157
- "pre-registered",
158
- "redirect_uri",
159
- "entity_id",
160
- "did",
161
- "verifier_attestation",
162
- "x509_san_dns",
163
- "x509_san_uri"
164
- ]).optional()
165
- }).strip();
155
+ response_mode: zOpenid4vpResponseModeDcApi,
156
+ // Not allowed with dc_api, but added to make working with interfaces easier
157
+ client_id_scheme: z5.never().optional(),
158
+ scope: z5.never().optional()
159
+ // TODO: should we disallow any properties specifically, such as redirect_uri and response_uri?
160
+ });
166
161
  function isOpenid4vpAuthorizationRequestDcApi(request) {
167
- return request.response_mode === "dc_api" || request.response_mode === "dc_api.jwt" || request.response_mode === "w3c_dc_api.jwt" || request.response_mode === "w3c_dc_api";
162
+ return request.response_mode !== void 0 && zOpenid4vpResponseModeDcApi.options.includes(
163
+ request.response_mode
164
+ );
168
165
  }
169
166
 
170
- // src/version.ts
171
- import { Oauth2ErrorCodes, Oauth2ServerErrorResponseError } from "@openid4vc/oauth2";
172
-
173
167
  // src/client-identifier-scheme/z-client-id-scheme.ts
174
168
  import { z as z6 } from "zod";
175
169
  var zClientIdScheme = z6.enum([
@@ -182,155 +176,114 @@ var zClientIdScheme = z6.enum([
182
176
  "x509_san_uri",
183
177
  "web-origin"
184
178
  ]);
185
-
186
- // src/version.ts
187
- function parseAuthorizationRequestVersion(request) {
188
- const requirements = [];
189
- if (isOpenid4vpAuthorizationRequestDcApi(request) && (request.response_mode === "w3c_dc_api" || request.response_mode === "w3c_dc_api.jwt")) {
190
- requirements.push(["<", 23]);
191
- requirements.push([">=", 21]);
192
- }
193
- if (isOpenid4vpAuthorizationRequestDcApi(request) && request.response_mode === "dc_api" || request.response_mode === "dc_api.jwt") {
194
- requirements.push([">=", 23]);
195
- }
196
- if (isOpenid4vpAuthorizationRequestDcApi(request) && (request.transaction_data || request.dcql_query)) {
197
- requirements.push([">=", 23]);
198
- }
199
- if (request.dcql_query) {
200
- requirements.push([">=", 22]);
201
- }
202
- if (request.transaction_data) {
203
- requirements.push([">=", 22]);
204
- }
205
- if (request.client_id_scheme) {
206
- requirements.push(["<", 22]);
207
- }
208
- if (request.client_id) {
209
- const colonIndex = request.client_id.indexOf(":");
210
- const schemePart = request.client_id.substring(0, colonIndex);
211
- const parsedScheme = zClientIdScheme.safeParse(schemePart);
212
- if (parsedScheme.success && parsedScheme.data !== "did" && parsedScheme.data !== "https") {
213
- requirements.push([">=", 22]);
214
- }
215
- }
216
- if (!request.client_id) {
217
- requirements.push([">=", 21]);
218
- }
219
- if ("client_metadata_uri" in request) {
220
- requirements.push(["<", 21]);
221
- }
222
- if (isOpenid4vpAuthorizationRequestDcApi(request)) {
223
- requirements.push([">=", 21]);
224
- }
225
- if ("request_uri_method" in request || "wallet_nonce" in request) {
226
- requirements.push([">=", 21]);
227
- }
228
- if (request.client_id_scheme === "verifier_attestation") {
229
- requirements.push([">=", 20]);
230
- }
231
- if (request.client_id_scheme === "x509_san_dns" || request.client_id_scheme === "x509_san_uri") {
232
- requirements.push([">=", 19]);
233
- }
234
- const lessThanVersions = requirements.filter(([operator]) => operator === "<").map(([_, version]) => version);
235
- const greaterThanVersions = requirements.filter(([operator]) => operator === ">=").map(([_, version]) => version);
236
- const highestPossibleVersion = lessThanVersions.length > 0 ? Math.max(Math.min(...lessThanVersions) - 1, 18) : 24;
237
- const lowestRequiredVersion = greaterThanVersions.length > 0 ? Math.max(...greaterThanVersions) : 18;
238
- if (lowestRequiredVersion > highestPossibleVersion) {
239
- throw new Oauth2ServerErrorResponseError({
240
- error: Oauth2ErrorCodes.InvalidRequest,
241
- error_description: "Could not infer openid4vp version from the openid4vp request payload."
242
- });
243
- }
244
- return highestPossibleVersion;
245
- }
179
+ var zLegacyClientIdScheme = z6.enum([
180
+ "pre-registered",
181
+ "redirect_uri",
182
+ "entity_id",
183
+ "did",
184
+ "verifier_attestation",
185
+ "x509_san_dns",
186
+ "x509_san_uri"
187
+ ]);
246
188
 
247
189
  // src/client-identifier-scheme/parse-client-identifier-scheme.ts
248
190
  function getOpenid4vpClientId(options) {
249
- const version = parseAuthorizationRequestVersion(options.authorizationRequestPayload);
250
- if (version < 22) {
251
- return getLegacyClientId(options);
252
- }
253
191
  if (isOpenid4vpAuthorizationRequestDcApi(options.authorizationRequestPayload)) {
254
192
  if (!options.origin) {
255
- throw new Oauth2ServerErrorResponseError2({
256
- error: Oauth2ErrorCodes2.InvalidRequest,
193
+ throw new Oauth2ServerErrorResponseError({
194
+ error: Oauth2ErrorCodes.InvalidRequest,
257
195
  error_description: "Failed to parse client identifier. 'origin' is required for requests with response_mode 'dc_api' and 'dc_api.jwt'"
258
196
  });
259
197
  }
260
- if (!options.jar || !options.authorizationRequestPayload.client_id) return `web-origin:${options.origin}`;
261
- return options.authorizationRequestPayload.client_id;
198
+ return {
199
+ clientId: options.authorizationRequestPayload.client_id ?? `web-origin:${options.origin}`
200
+ };
262
201
  }
263
- return options.authorizationRequestPayload.client_id;
264
- }
265
- function getLegacyClientId(options) {
266
- const legacyClientIdScheme = options.authorizationRequestPayload.client_id_scheme ?? "pre-registered";
267
- const clientIdScheme = legacyClientIdScheme === "entity_id" ? "https" : legacyClientIdScheme;
268
- if (isOpenid4vpAuthorizationRequestDcApi(options.authorizationRequestPayload)) {
269
- if (!options.origin) {
270
- throw new Oauth2ServerErrorResponseError2({
271
- error: Oauth2ErrorCodes2.InvalidRequest,
272
- error_description: "Failed to parse client identifier. 'origin' is required for requests with response_mode 'dc_api' and 'dc_api.jwt'"
202
+ if (!options.authorizationRequestPayload.client_id) {
203
+ throw new Oauth2ServerErrorResponseError({
204
+ error: Oauth2ErrorCodes.InvalidRequest,
205
+ error_description: `Failed to parse client identifier. Missing required client_id parameter for response_mode '${options.authorizationRequestPayload.response_mode}'.`
206
+ });
207
+ }
208
+ if (options.authorizationRequestPayload.client_id_scheme) {
209
+ const parsedClientIdScheme = zLegacyClientIdScheme.safeParse(options.authorizationRequestPayload.client_id_scheme);
210
+ if (!parsedClientIdScheme.success) {
211
+ throw new Oauth2ServerErrorResponseError({
212
+ error: Oauth2ErrorCodes.InvalidRequest,
213
+ error_description: `Failed to parse client identifier. Unsupported client_id_scheme value '${options.authorizationRequestPayload.client_id_scheme}'.`
273
214
  });
274
215
  }
275
- if (!options.jar || !options.authorizationRequestPayload.client_id) return `web-origin:${options.origin}`;
276
- return `${clientIdScheme}:${options.authorizationRequestPayload.client_id}`;
277
- }
278
- if (clientIdScheme === "https" || clientIdScheme === "did") {
279
- return options.authorizationRequestPayload.client_id;
280
- }
281
- if (clientIdScheme === "pre-registered") {
282
- return options.authorizationRequestPayload.client_id;
216
+ const clientIdScheme = parsedClientIdScheme.data === "entity_id" ? "https" : parsedClientIdScheme.data;
217
+ if (clientIdScheme === "https" || clientIdScheme === "did" || clientIdScheme === "pre-registered") {
218
+ return { clientId: options.authorizationRequestPayload.client_id };
219
+ }
220
+ return {
221
+ clientId: `${clientIdScheme}:${options.authorizationRequestPayload.client_id}`,
222
+ legacyClientId: options.authorizationRequestPayload.client_id
223
+ };
283
224
  }
284
- return `${clientIdScheme}:${options.authorizationRequestPayload.client_id}`;
225
+ return {
226
+ clientId: options.authorizationRequestPayload.client_id
227
+ };
285
228
  }
286
229
  function parseClientIdentifier(options, parserConfig) {
287
- const { authorizationRequestPayload, jar } = options;
230
+ const { authorizationRequestPayload, jar, origin } = options;
288
231
  const parserConfigWithDefaults = {
289
232
  supportedSchemes: parserConfig?.supportedSchemes || Object.values(zClientIdScheme.options)
290
233
  };
291
- const clientId = getOpenid4vpClientId(options);
234
+ const { clientId, legacyClientId } = getOpenid4vpClientId({
235
+ authorizationRequestPayload,
236
+ origin
237
+ });
292
238
  const colonIndex = clientId.indexOf(":");
293
239
  if (colonIndex === -1) {
294
240
  return {
295
241
  scheme: "pre-registered",
296
242
  identifier: clientId,
297
243
  originalValue: clientId,
244
+ legacyClientId,
298
245
  clientMetadata: authorizationRequestPayload.client_metadata
299
246
  };
300
247
  }
301
248
  const schemePart = clientId.substring(0, colonIndex);
302
249
  const identifierPart = clientId.substring(colonIndex + 1);
303
250
  if (!parserConfigWithDefaults.supportedSchemes.includes(schemePart)) {
304
- throw new Oauth2ServerErrorResponseError2({
305
- error: Oauth2ErrorCodes2.InvalidRequest,
251
+ throw new Oauth2ServerErrorResponseError({
252
+ error: Oauth2ErrorCodes.InvalidRequest,
306
253
  error_description: `Unsupported client identifier scheme. ${schemePart} is not supported.`
307
254
  });
308
255
  }
309
256
  const scheme = schemePart;
310
257
  if (scheme === "https") {
311
- if (!clientId.startsWith("https://") && !(getGlobalConfig().allowInsecureUrls && clientId.startsWith("http://"))) {
312
- throw new Oauth2ServerErrorResponseError2({
313
- error: Oauth2ErrorCodes2.InvalidRequest,
314
- error_description: "Invalid client identifier. Client identifier must start with https:// or http:// if allowInsecureUrls is true."
315
- });
258
+ if (!zHttpsUrl3.safeParse(clientId).success) {
259
+ throw new Oauth2ServerErrorResponseError(
260
+ {
261
+ error: Oauth2ErrorCodes.InvalidRequest,
262
+ error_description: "Invalid client identifier. Client identifier must start with https://"
263
+ },
264
+ {
265
+ internalMessage: `Insecure http:// urls can be enabled by setting the 'allowInsecureUrls' option using setGlobalConfig`
266
+ }
267
+ );
316
268
  }
317
269
  return {
318
270
  scheme,
319
271
  identifier: clientId,
320
272
  originalValue: clientId,
273
+ legacyClientId,
321
274
  trustChain: authorizationRequestPayload.trust_chain
322
275
  };
323
276
  }
324
277
  if (scheme === "redirect_uri") {
325
278
  if (jar) {
326
- throw new Oauth2ServerErrorResponseError2({
327
- error: Oauth2ErrorCodes2.InvalidRequest,
279
+ throw new Oauth2ServerErrorResponseError({
280
+ error: Oauth2ErrorCodes.InvalidRequest,
328
281
  error_description: 'Using client identifier scheme "redirect_uri" the request MUST NOT be signed.'
329
282
  });
330
283
  }
331
284
  if (isOpenid4vpAuthorizationRequestDcApi(authorizationRequestPayload)) {
332
- throw new Oauth2ServerErrorResponseError2({
333
- error: Oauth2ErrorCodes2.InvalidRequest,
285
+ throw new Oauth2ServerErrorResponseError({
286
+ error: Oauth2ErrorCodes.InvalidRequest,
334
287
  error_description: `The client identifier scheme 'redirect_uri' is not supported when using the dc_api response mode.`
335
288
  });
336
289
  }
@@ -338,31 +291,32 @@ function parseClientIdentifier(options, parserConfig) {
338
291
  scheme,
339
292
  identifier: identifierPart,
340
293
  originalValue: clientId,
294
+ legacyClientId,
341
295
  redirectUri: authorizationRequestPayload.redirect_uri ?? authorizationRequestPayload.response_uri
342
296
  };
343
297
  }
344
298
  if (scheme === "did") {
345
299
  if (!jar) {
346
- throw new Oauth2ServerErrorResponseError2({
347
- error: Oauth2ErrorCodes2.InvalidRequest,
300
+ throw new Oauth2ServerErrorResponseError({
301
+ error: Oauth2ErrorCodes.InvalidRequest,
348
302
  error_description: 'Using client identifier scheme "did" requires a signed JAR request.'
349
303
  });
350
304
  }
351
305
  if (!clientId.startsWith("did:")) {
352
- throw new Oauth2ServerErrorResponseError2({
353
- error: Oauth2ErrorCodes2.InvalidRequest,
306
+ throw new Oauth2ServerErrorResponseError({
307
+ error: Oauth2ErrorCodes.InvalidRequest,
354
308
  error_description: "Invalid client identifier. Client identifier must start with 'did:'"
355
309
  });
356
310
  }
357
311
  if (!jar.signer.publicJwk.kid) {
358
- throw new Oauth2ServerErrorResponseError2({
359
- error: Oauth2ErrorCodes2.InvalidRequest,
312
+ throw new Oauth2ServerErrorResponseError({
313
+ error: Oauth2ErrorCodes.InvalidRequest,
360
314
  error_description: `Missing required 'kid' for client identifier scheme: did`
361
315
  });
362
316
  }
363
317
  if (!jar.signer.publicJwk.kid?.startsWith(clientId)) {
364
- throw new Oauth2ServerErrorResponseError2({
365
- error: Oauth2ErrorCodes2.InvalidRequest,
318
+ throw new Oauth2ServerErrorResponseError({
319
+ error: Oauth2ErrorCodes.InvalidRequest,
366
320
  error_description: 'With client identifier scheme "did" the JAR request must be signed by the same DID as the client identifier.'
367
321
  });
368
322
  }
@@ -370,27 +324,28 @@ function parseClientIdentifier(options, parserConfig) {
370
324
  scheme,
371
325
  identifier: clientId,
372
326
  originalValue: clientId,
327
+ legacyClientId,
373
328
  didUrl: jar.signer.publicJwk.kid
374
329
  };
375
330
  }
376
331
  if (scheme === "x509_san_dns" || scheme === "x509_san_uri") {
377
332
  if (!jar) {
378
- throw new Oauth2ServerErrorResponseError2({
379
- error: Oauth2ErrorCodes2.InvalidRequest,
333
+ throw new Oauth2ServerErrorResponseError({
334
+ error: Oauth2ErrorCodes.InvalidRequest,
380
335
  error_description: 'Using client identifier scheme "x509_san_dns" or "x509_san_uri" requires a signed JAR request.'
381
336
  });
382
337
  }
383
338
  if (jar.signer.method !== "x5c") {
384
- throw new Oauth2ServerErrorResponseError2({
385
- error: Oauth2ErrorCodes2.InvalidRequest,
339
+ throw new Oauth2ServerErrorResponseError({
340
+ error: Oauth2ErrorCodes.InvalidRequest,
386
341
  error_description: "Something went wrong. The JWT signer method is not x5c but the client identifier scheme is x509_san_dns."
387
342
  });
388
343
  }
389
344
  if (scheme === "x509_san_dns") {
390
345
  if (!options.callbacks.getX509CertificateMetadata) {
391
- throw new Oauth2ServerErrorResponseError2(
346
+ throw new Oauth2ServerErrorResponseError(
392
347
  {
393
- error: Oauth2ErrorCodes2.ServerError
348
+ error: Oauth2ErrorCodes.ServerError
394
349
  },
395
350
  {
396
351
  internalMessage: "Missing required 'getX509CertificateMetadata' callback for verification of 'x509_san_dns' client id scheme"
@@ -399,25 +354,25 @@ function parseClientIdentifier(options, parserConfig) {
399
354
  }
400
355
  const { sanDnsNames } = options.callbacks.getX509CertificateMetadata(jar.signer.x5c[0]);
401
356
  if (!sanDnsNames.includes(identifierPart)) {
402
- throw new Oauth2ServerErrorResponseError2({
403
- error: Oauth2ErrorCodes2.InvalidRequest,
357
+ throw new Oauth2ServerErrorResponseError({
358
+ error: Oauth2ErrorCodes.InvalidRequest,
404
359
  error_description: `Invalid client identifier. One of the leaf certificates san dns names [${sanDnsNames.join(", ")}] must match the client identifier '${identifierPart}'. `
405
360
  });
406
361
  }
407
362
  if (!isOpenid4vpAuthorizationRequestDcApi(authorizationRequestPayload)) {
408
363
  const uri = authorizationRequestPayload.redirect_uri ?? authorizationRequestPayload.response_uri;
409
364
  if (!uri || new URL2(uri).hostname !== identifierPart) {
410
- throw new Oauth2ServerErrorResponseError2({
411
- error: Oauth2ErrorCodes2.InvalidRequest,
365
+ throw new Oauth2ServerErrorResponseError({
366
+ error: Oauth2ErrorCodes.InvalidRequest,
412
367
  error_description: "Invalid client identifier. The fully qualified domain name of the redirect_uri value MUST match the Client Identifier without the prefix x509_san_dns."
413
368
  });
414
369
  }
415
370
  }
416
371
  } else if (scheme === "x509_san_uri") {
417
372
  if (!options.callbacks.getX509CertificateMetadata) {
418
- throw new Oauth2ServerErrorResponseError2(
373
+ throw new Oauth2ServerErrorResponseError(
419
374
  {
420
- error: Oauth2ErrorCodes2.ServerError
375
+ error: Oauth2ErrorCodes.ServerError
421
376
  },
422
377
  {
423
378
  internalMessage: "Missing required 'getX509CertificateMetadata' callback for verification of 'x509_san_uri' client id scheme"
@@ -426,16 +381,16 @@ function parseClientIdentifier(options, parserConfig) {
426
381
  }
427
382
  const { sanUriNames } = options.callbacks.getX509CertificateMetadata(jar.signer.x5c[0]);
428
383
  if (!sanUriNames.includes(identifierPart)) {
429
- throw new Oauth2ServerErrorResponseError2({
430
- error: Oauth2ErrorCodes2.InvalidRequest,
384
+ throw new Oauth2ServerErrorResponseError({
385
+ error: Oauth2ErrorCodes.InvalidRequest,
431
386
  error_description: `Invalid client identifier. One of the leaf certificates san uri names [${sanUriNames.join(", ")}] must match the client identifier '${identifierPart}'.`
432
387
  });
433
388
  }
434
389
  if (!isOpenid4vpAuthorizationRequestDcApi(authorizationRequestPayload)) {
435
390
  const uri = authorizationRequestPayload.redirect_uri || authorizationRequestPayload.response_uri;
436
391
  if (!uri || uri !== identifierPart) {
437
- throw new Oauth2ServerErrorResponseError2({
438
- error: Oauth2ErrorCodes2.InvalidRequest,
392
+ throw new Oauth2ServerErrorResponseError({
393
+ error: Oauth2ErrorCodes.InvalidRequest,
439
394
  error_description: "The redirect_uri value MUST match the Client Identifier without the prefix x509_san_uri"
440
395
  });
441
396
  }
@@ -445,6 +400,7 @@ function parseClientIdentifier(options, parserConfig) {
445
400
  scheme,
446
401
  identifier: identifierPart,
447
402
  originalValue: clientId,
403
+ legacyClientId,
448
404
  x5c: jar.signer.x5c
449
405
  };
450
406
  }
@@ -453,13 +409,14 @@ function parseClientIdentifier(options, parserConfig) {
453
409
  scheme,
454
410
  identifier: identifierPart,
455
411
  originalValue: clientId,
412
+ legacyClientId,
456
413
  clientMetadata: authorizationRequestPayload.client_metadata
457
414
  };
458
415
  }
459
416
  if (scheme === "verifier_attestation") {
460
417
  if (!jar) {
461
- throw new Oauth2ServerErrorResponseError2({
462
- error: Oauth2ErrorCodes2.InvalidRequest,
418
+ throw new Oauth2ServerErrorResponseError({
419
+ error: Oauth2ErrorCodes.InvalidRequest,
463
420
  error_description: 'Using client identifier scheme "verifier_attestation" requires a signed JAR request.'
464
421
  });
465
422
  }
@@ -467,6 +424,7 @@ function parseClientIdentifier(options, parserConfig) {
467
424
  return {
468
425
  scheme,
469
426
  identifier: identifierPart,
427
+ legacyClientId,
470
428
  originalValue: clientId
471
429
  };
472
430
  }
@@ -622,94 +580,94 @@ async function createJarAuthorizationRequest(options) {
622
580
  }
623
581
 
624
582
  // src/authorization-request/validate-authorization-request.ts
625
- import { Oauth2ErrorCodes as Oauth2ErrorCodes3, Oauth2ServerErrorResponseError as Oauth2ServerErrorResponseError3 } from "@openid4vc/oauth2";
626
- import { zHttpsUrl as zHttpsUrl3 } from "@openid4vc/utils";
583
+ import { Oauth2ErrorCodes as Oauth2ErrorCodes2, Oauth2ServerErrorResponseError as Oauth2ServerErrorResponseError2 } from "@openid4vc/oauth2";
584
+ import { zHttpsUrl as zHttpsUrl4 } from "@openid4vc/utils";
627
585
  var validateOpenid4vpAuthorizationRequestPayload = (options) => {
628
586
  const { params, walletVerificationOptions } = options;
629
587
  if (!params.redirect_uri && !params.response_uri) {
630
- throw new Oauth2ServerErrorResponseError3({
631
- error: Oauth2ErrorCodes3.InvalidRequest,
588
+ throw new Oauth2ServerErrorResponseError2({
589
+ error: Oauth2ErrorCodes2.InvalidRequest,
632
590
  error_description: `Missing required 'redirect_uri' or 'response_uri' in openid4vp authorization request.`
633
591
  });
634
592
  }
635
593
  if (params.response_uri && !["direct_post", "direct_post.jwt"].find((mode) => mode === params.response_mode)) {
636
- throw new Oauth2ServerErrorResponseError3({
637
- error: Oauth2ErrorCodes3.InvalidRequest,
594
+ throw new Oauth2ServerErrorResponseError2({
595
+ error: Oauth2ErrorCodes2.InvalidRequest,
638
596
  error_description: `The 'response_mode' parameter MUST be 'direct_post' or 'direct_post.jwt' when 'response_uri' is provided. Current: ${params.response_mode}`
639
597
  });
640
598
  }
641
599
  if ([params.presentation_definition_uri, params.presentation_definition, params.dcql_query, params.scope].filter(
642
600
  Boolean
643
601
  ).length > 1) {
644
- throw new Oauth2ServerErrorResponseError3({
645
- error: Oauth2ErrorCodes3.InvalidRequest,
602
+ throw new Oauth2ServerErrorResponseError2({
603
+ error: Oauth2ErrorCodes2.InvalidRequest,
646
604
  error_description: "Exactly one of the following parameters MUST be present in the authorization request: dcql_query, presentation_definition, presentation_definition_uri, or a scope value representing a Presentation Definition."
647
605
  });
648
606
  }
649
607
  if (params.request_uri_method && !params.request_uri) {
650
- throw new Oauth2ServerErrorResponseError3({
651
- error: Oauth2ErrorCodes3.InvalidRequest,
608
+ throw new Oauth2ServerErrorResponseError2({
609
+ error: Oauth2ErrorCodes2.InvalidRequest,
652
610
  error_description: 'The "request_uri_method" parameter MUST NOT be present in the authorization request if the "request_uri" parameter is not present.'
653
611
  });
654
612
  }
655
613
  if (params.request_uri_method && !["GET", "POST"].includes(params.request_uri_method)) {
656
- throw new Oauth2ServerErrorResponseError3({
657
- error: Oauth2ErrorCodes3.InvalidRequestUriMethod,
614
+ throw new Oauth2ServerErrorResponseError2({
615
+ error: Oauth2ErrorCodes2.InvalidRequestUriMethod,
658
616
  error_description: `The 'request_uri_method' parameter MUST be 'GET' or 'POST'. Current: ${params.request_uri_method}`
659
617
  });
660
618
  }
661
- if (params.trust_chain && !zHttpsUrl3.safeParse(params.client_id).success) {
662
- throw new Oauth2ServerErrorResponseError3({
663
- error: Oauth2ErrorCodes3.InvalidRequest,
619
+ if (params.trust_chain && !zHttpsUrl4.safeParse(params.client_id).success) {
620
+ throw new Oauth2ServerErrorResponseError2({
621
+ error: Oauth2ErrorCodes2.InvalidRequest,
664
622
  error_description: 'The "trust_chain" parameter MUST NOT be present in the authorization request if the "client_id" is not an OpenId Federation Entity Identifier starting with http:// or https://.'
665
623
  });
666
624
  }
667
625
  if (walletVerificationOptions?.expectedNonce && !params.wallet_nonce) {
668
- throw new Oauth2ServerErrorResponseError3({
669
- error: Oauth2ErrorCodes3.InvalidRequest,
626
+ throw new Oauth2ServerErrorResponseError2({
627
+ error: Oauth2ErrorCodes2.InvalidRequest,
670
628
  error_description: 'The "wallet_nonce" parameter MUST be present in the authorization request when the "expectedNonce" parameter is provided.'
671
629
  });
672
630
  }
673
631
  if (walletVerificationOptions?.expectedNonce !== params.wallet_nonce) {
674
- throw new Oauth2ServerErrorResponseError3({
675
- error: Oauth2ErrorCodes3.InvalidRequest,
632
+ throw new Oauth2ServerErrorResponseError2({
633
+ error: Oauth2ErrorCodes2.InvalidRequest,
676
634
  error_description: 'The "wallet_nonce" parameter MUST match the "expectedNonce" parameter when the "expectedNonce" parameter is provided.'
677
635
  });
678
636
  }
679
637
  if (params.client_id.startsWith("web-origin:")) {
680
- throw new Oauth2ServerErrorResponseError3({
681
- error: Oauth2ErrorCodes3.InvalidRequest,
638
+ throw new Oauth2ServerErrorResponseError2({
639
+ error: Oauth2ErrorCodes2.InvalidRequest,
682
640
  error_description: `The 'client_id' parameter MUST NOT use client identifier scheme 'web-origin' when not using the dc_api response mode. Current: ${params.client_id}`
683
641
  });
684
642
  }
685
643
  };
686
644
 
687
645
  // src/authorization-request/validate-authorization-request-dc-api.ts
688
- import { Oauth2ErrorCodes as Oauth2ErrorCodes4, Oauth2ServerErrorResponseError as Oauth2ServerErrorResponseError4 } from "@openid4vc/oauth2";
646
+ import { Oauth2ErrorCodes as Oauth2ErrorCodes3, Oauth2ServerErrorResponseError as Oauth2ServerErrorResponseError3 } from "@openid4vc/oauth2";
689
647
  var validateOpenid4vpAuthorizationRequestDcApiPayload = (options) => {
690
648
  const { params, isJarRequest, disableOriginValidation, origin } = options;
691
649
  if (isJarRequest && !params.expected_origins) {
692
- throw new Oauth2ServerErrorResponseError4({
693
- error: Oauth2ErrorCodes4.InvalidRequest,
650
+ throw new Oauth2ServerErrorResponseError3({
651
+ error: Oauth2ErrorCodes3.InvalidRequest,
694
652
  error_description: `The 'expected_origins' parameter MUST be present when using the dc_api response mode in combinaction with jar.`
695
653
  });
696
654
  }
697
655
  if ([params.presentation_definition, params.dcql_query].filter(Boolean).length !== 1) {
698
- throw new Oauth2ServerErrorResponseError4({
699
- error: Oauth2ErrorCodes4.InvalidRequest,
656
+ throw new Oauth2ServerErrorResponseError3({
657
+ error: Oauth2ErrorCodes3.InvalidRequest,
700
658
  error_description: "Exactly one of the following parameters MUST be present in the Authorization Request: dcql_query or presentation_definition"
701
659
  });
702
660
  }
703
661
  if (params.expected_origins && !disableOriginValidation) {
704
662
  if (!origin) {
705
- throw new Oauth2ServerErrorResponseError4({
706
- error: Oauth2ErrorCodes4.InvalidRequest,
663
+ throw new Oauth2ServerErrorResponseError3({
664
+ error: Oauth2ErrorCodes3.InvalidRequest,
707
665
  error_description: `Failed to validate the 'origin' of the authorization request. The 'origin' was not provided.`
708
666
  });
709
667
  }
710
668
  if (params.expected_origins && !params.expected_origins.includes(origin)) {
711
- throw new Oauth2ServerErrorResponseError4({
712
- error: Oauth2ErrorCodes4.InvalidRequest,
669
+ throw new Oauth2ServerErrorResponseError3({
670
+ error: Oauth2ErrorCodes3.InvalidRequest,
713
671
  error_description: `The 'expected_origins' parameter MUST include the origin of the authorization request. Current: ${params.expected_origins.join(", ")}`
714
672
  });
715
673
  }
@@ -789,25 +747,25 @@ import { parseWithErrorHandling as parseWithErrorHandling3 } from "@openid4vc/ut
789
747
  import z10 from "zod";
790
748
 
791
749
  // src/jar/z-jar-authorization-request.ts
792
- import { Oauth2ServerErrorResponseError as Oauth2ServerErrorResponseError5 } from "@openid4vc/oauth2";
793
- import { zHttpsUrl as zHttpsUrl4 } from "@openid4vc/utils";
750
+ import { Oauth2ServerErrorResponseError as Oauth2ServerErrorResponseError4 } from "@openid4vc/oauth2";
751
+ import { zHttpsUrl as zHttpsUrl5 } from "@openid4vc/utils";
794
752
  import { z as z9 } from "zod";
795
753
  var zJarAuthorizationRequest = z9.object({
796
754
  request: z9.optional(z9.string()),
797
- request_uri: z9.optional(zHttpsUrl4),
755
+ request_uri: z9.optional(zHttpsUrl5),
798
756
  request_uri_method: z9.optional(z9.string()),
799
757
  client_id: z9.optional(z9.string())
800
758
  }).passthrough();
801
759
  function validateJarRequestParams(options) {
802
760
  const { jarRequestParams } = options;
803
761
  if (jarRequestParams.request && jarRequestParams.request_uri) {
804
- throw new Oauth2ServerErrorResponseError5({
762
+ throw new Oauth2ServerErrorResponseError4({
805
763
  error: "invalid_request_object",
806
764
  error_description: "request and request_uri cannot both be present in a JAR request"
807
765
  });
808
766
  }
809
767
  if (!jarRequestParams.request && !jarRequestParams.request_uri) {
810
- throw new Oauth2ServerErrorResponseError5({
768
+ throw new Oauth2ServerErrorResponseError4({
811
769
  error: "invalid_request_object",
812
770
  error_description: "request or request_uri must be present"
813
771
  });
@@ -870,7 +828,7 @@ import { parseWithErrorHandling as parseWithErrorHandling4 } from "@openid4vc/ut
870
828
  import z14 from "zod";
871
829
 
872
830
  // src/fetch-client-metadata.ts
873
- import { Oauth2ErrorCodes as Oauth2ErrorCodes5, Oauth2ServerErrorResponseError as Oauth2ServerErrorResponseError6 } from "@openid4vc/oauth2";
831
+ import { Oauth2ErrorCodes as Oauth2ErrorCodes4, Oauth2ServerErrorResponseError as Oauth2ServerErrorResponseError5 } from "@openid4vc/oauth2";
874
832
  import { ContentType, createZodFetcher } from "@openid4vc/utils";
875
833
  async function fetchClientMetadata(options) {
876
834
  const { fetch, clientMetadataUri } = options;
@@ -882,15 +840,15 @@ async function fetchClientMetadata(options) {
882
840
  }
883
841
  });
884
842
  if (!response.ok) {
885
- throw new Oauth2ServerErrorResponseError6({
843
+ throw new Oauth2ServerErrorResponseError5({
886
844
  error_description: `Fetching client metadata from '${clientMetadataUri}' failed with status code '${response.status}'.`,
887
- error: Oauth2ErrorCodes5.InvalidRequestUri
845
+ error: Oauth2ErrorCodes4.InvalidRequestUri
888
846
  });
889
847
  }
890
848
  if (!result || !result.success) {
891
- throw new Oauth2ServerErrorResponseError6({
849
+ throw new Oauth2ServerErrorResponseError5({
892
850
  error_description: `Parsing client metadata from '${clientMetadataUri}' failed.`,
893
- error: Oauth2ErrorCodes5.InvalidRequestObject
851
+ error: Oauth2ErrorCodes4.InvalidRequestObject
894
852
  });
895
853
  }
896
854
  return result.data;
@@ -907,6 +865,68 @@ import {
907
865
  zCompactJwt as zCompactJwt2
908
866
  } from "@openid4vc/oauth2";
909
867
 
868
+ // src/version.ts
869
+ import { Oauth2ErrorCodes as Oauth2ErrorCodes5, Oauth2ServerErrorResponseError as Oauth2ServerErrorResponseError6 } from "@openid4vc/oauth2";
870
+ function parseAuthorizationRequestVersion(request) {
871
+ const requirements = [];
872
+ if (isOpenid4vpAuthorizationRequestDcApi(request) && (request.response_mode === "w3c_dc_api" || request.response_mode === "w3c_dc_api.jwt")) {
873
+ requirements.push(["<", 23]);
874
+ requirements.push([">=", 21]);
875
+ }
876
+ if (isOpenid4vpAuthorizationRequestDcApi(request) && request.response_mode === "dc_api" || request.response_mode === "dc_api.jwt") {
877
+ requirements.push([">=", 23]);
878
+ }
879
+ if (isOpenid4vpAuthorizationRequestDcApi(request) && (request.transaction_data || request.dcql_query)) {
880
+ requirements.push([">=", 23]);
881
+ }
882
+ if (request.dcql_query) {
883
+ requirements.push([">=", 22]);
884
+ }
885
+ if (request.transaction_data) {
886
+ requirements.push([">=", 22]);
887
+ }
888
+ if (request.client_id_scheme) {
889
+ requirements.push(["<", 22]);
890
+ }
891
+ if (request.client_id) {
892
+ const colonIndex = request.client_id.indexOf(":");
893
+ const schemePart = request.client_id.substring(0, colonIndex);
894
+ const parsedScheme = zClientIdScheme.safeParse(schemePart);
895
+ if (parsedScheme.success && parsedScheme.data !== "did" && parsedScheme.data !== "https") {
896
+ requirements.push([">=", 22]);
897
+ }
898
+ }
899
+ if (!request.client_id) {
900
+ requirements.push([">=", 21]);
901
+ }
902
+ if (request.client_metadata_uri) {
903
+ requirements.push(["<", 21]);
904
+ }
905
+ if (isOpenid4vpAuthorizationRequestDcApi(request)) {
906
+ requirements.push([">=", 21]);
907
+ }
908
+ if (request.request_uri_method || request.wallet_nonce) {
909
+ requirements.push([">=", 21]);
910
+ }
911
+ if (request.client_id_scheme === "verifier_attestation") {
912
+ requirements.push([">=", 20]);
913
+ }
914
+ if (request.client_id_scheme === "x509_san_dns" || request.client_id_scheme === "x509_san_uri") {
915
+ requirements.push([">=", 19]);
916
+ }
917
+ const lessThanVersions = requirements.filter(([operator]) => operator === "<").map(([_, version]) => version);
918
+ const greaterThanVersions = requirements.filter(([operator]) => operator === ">=").map(([_, version]) => version);
919
+ const highestPossibleVersion = lessThanVersions.length > 0 ? Math.max(Math.min(...lessThanVersions) - 1, 18) : 24;
920
+ const lowestRequiredVersion = greaterThanVersions.length > 0 ? Math.max(...greaterThanVersions) : 18;
921
+ if (lowestRequiredVersion > highestPossibleVersion) {
922
+ throw new Oauth2ServerErrorResponseError6({
923
+ error: Oauth2ErrorCodes5.InvalidRequest,
924
+ error_description: "Could not infer openid4vp version from the openid4vp request payload."
925
+ });
926
+ }
927
+ return highestPossibleVersion;
928
+ }
929
+
910
930
  // src/jar/jar-request-object/fetch-jar-request-object.ts
911
931
  import { Oauth2ErrorCodes as Oauth2ErrorCodes6, Oauth2ServerErrorResponseError as Oauth2ServerErrorResponseError7 } from "@openid4vc/oauth2";
912
932
  import { ContentType as ContentType2, createZodFetcher as createZodFetcher2, objectToQueryParams as objectToQueryParams2 } from "@openid4vc/utils";
@@ -955,7 +975,7 @@ async function verifyJarRequest(options) {
955
975
  const { callbacks, wallet = {} } = options;
956
976
  const jarRequestParams = validateJarRequestParams(options);
957
977
  const sendBy = jarRequestParams.request ? "value" : "reference";
958
- const clientIdentifierScheme = jarRequestParams.client_id ? zClientIdScheme.parse(jarRequestParams.client_id.split(":")[0]) : "web-origin";
978
+ const clientIdentifierScheme = jarRequestParams.client_id ? zClientIdScheme.safeParse(jarRequestParams.client_id.split(":")[0]).data : "web-origin";
959
979
  const method = jarRequestParams.request_uri_method ?? "GET";
960
980
  if (method !== "GET" && method !== "POST") {
961
981
  throw new Oauth2ServerErrorResponseError8({
@@ -1263,7 +1283,7 @@ async function createOpenid4vpAuthorizationResponse(options) {
1263
1283
  const { authorizationRequestPayload, jarm, callbacks } = options;
1264
1284
  const authorizationResponsePayload = {
1265
1285
  ...options.authorizationResponsePayload,
1266
- ..."state" in authorizationRequestPayload && { state: authorizationRequestPayload.state }
1286
+ state: authorizationRequestPayload.state
1267
1287
  };
1268
1288
  if (authorizationRequestPayload.response_mode && isJarmResponseMode(authorizationRequestPayload.response_mode) && !jarm) {
1269
1289
  throw new Oauth2Error7(
@@ -1447,7 +1467,7 @@ function parseDcqlVpToken(vpToken) {
1447
1467
  // src/authorization-response/validate-authorization-response.ts
1448
1468
  function validateOpenid4vpAuthorizationResponsePayload(options) {
1449
1469
  const { authorizationRequestPayload, authorizationResponsePayload } = options;
1450
- if ("state" in authorizationRequestPayload && authorizationRequestPayload.state !== authorizationResponsePayload.state) {
1470
+ if (authorizationRequestPayload.state && authorizationRequestPayload.state !== authorizationResponsePayload.state) {
1451
1471
  throw new Oauth2Error10("OpenId4Vp Authorization Response state mismatch.");
1452
1472
  }
1453
1473
  if (authorizationResponsePayload.id_token) {
@@ -1459,7 +1479,7 @@ function validateOpenid4vpAuthorizationResponsePayload(options) {
1459
1479
  }
1460
1480
  return {
1461
1481
  type: "pex",
1462
- pex: "scope" in authorizationRequestPayload && authorizationRequestPayload.scope ? {
1482
+ pex: authorizationRequestPayload.scope ? {
1463
1483
  scope: authorizationRequestPayload.scope,
1464
1484
  presentationSubmission: authorizationResponsePayload.presentation_submission,
1465
1485
  presentations: parsePexVpToken(authorizationResponsePayload.vp_token)
@@ -1474,7 +1494,7 @@ function validateOpenid4vpAuthorizationResponsePayload(options) {
1474
1494
  const presentations = parseDcqlVpToken(authorizationResponsePayload.vp_token);
1475
1495
  return {
1476
1496
  type: "dcql",
1477
- dcql: "scope" in authorizationRequestPayload && authorizationRequestPayload.scope ? {
1497
+ dcql: authorizationRequestPayload.scope ? {
1478
1498
  scope: authorizationRequestPayload.scope,
1479
1499
  presentations
1480
1500
  } : {
@@ -1568,13 +1588,18 @@ async function parseJarmAuthorizationResponse(options) {
1568
1588
  // src/authorization-response/parse-authorization-response.ts
1569
1589
  async function parseOpenid4vpAuthorizationResponse(options) {
1570
1590
  const { authorizationResponse, callbacks, authorizationRequestPayload, origin } = options;
1571
- const expectedClientId = getOpenid4vpClientId({ authorizationRequestPayload, origin });
1591
+ const expectedClientId = getOpenid4vpClientId({
1592
+ origin,
1593
+ authorizationRequestPayload
1594
+ });
1572
1595
  if (authorizationResponse.response) {
1573
1596
  return parseJarmAuthorizationResponse({
1574
1597
  jarmResponseJwt: authorizationResponse.response,
1575
1598
  callbacks,
1576
1599
  authorizationRequestPayload,
1577
- expectedClientId
1600
+ // If client_id_scheme was provided we should use the legacy (unprefixed) client id scheme
1601
+ // TODO: allow both versions, in case of e.g. did:
1602
+ expectedClientId: expectedClientId.legacyClientId ?? expectedClientId.clientId
1578
1603
  });
1579
1604
  }
1580
1605
  const authorizationResponsePayload = parseOpenid4VpAuthorizationResponsePayload(authorizationResponse);