@openid4vc/openid4vp 0.3.0-alpha-20250707100752 → 0.3.0-alpha-20250707121837

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,7 @@
1
- // src/client-identifier-scheme/parse-client-identifier-scheme.ts
1
+ // src/client-identifier-prefix/parse-client-identifier-prefix.ts
2
2
  import { Oauth2ErrorCodes, Oauth2ServerErrorResponseError } from "@openid4vc/oauth2";
3
- import { URL as URL2, zHttpsUrl as zHttpsUrl3 } from "@openid4vc/utils";
3
+ import { HashAlgorithm } from "@openid4vc/oauth2";
4
+ import { URL as URL2, decodeBase64, encodeToBase64Url, zHttpsUrl as zHttpsUrl3 } from "@openid4vc/utils";
4
5
 
5
6
  // src/authorization-request/z-authorization-request-dc-api.ts
6
7
  import { z as z6 } from "zod";
@@ -54,7 +55,7 @@ var zJarmClientMetadataParsed = zJarmClientMetadata.transform((client_metadata)
54
55
  type: "sign_encrypt",
55
56
  client_metadata: {
56
57
  ...SignEncrypt.data,
57
- authorization_encrypted_response_enc: client_metadata.authorization_encrypted_response_enc ?? "A128CBC-HS256"
58
+ authorization_encrypted_response_enc: client_metadata.authorization_encrypted_response_enc
58
59
  }
59
60
  };
60
61
  }
@@ -64,7 +65,7 @@ var zJarmClientMetadataParsed = zJarmClientMetadata.transform((client_metadata)
64
65
  type: "encrypt",
65
66
  client_metadata: {
66
67
  ...encryptOnly.data,
67
- authorization_encrypted_response_enc: parsedClientMeta.authorization_encrypted_response_enc ?? "A128CBC-HS256"
68
+ authorization_encrypted_response_enc: parsedClientMeta.authorization_encrypted_response_enc
68
69
  }
69
70
  };
70
71
  }
@@ -74,7 +75,7 @@ var zJarmClientMetadataParsed = zJarmClientMetadata.transform((client_metadata)
74
75
  type: "sign",
75
76
  client_metadata: {
76
77
  ...signOnly.data,
77
- authorization_signed_response_alg: parsedClientMeta.authorization_signed_response_alg ?? "RS256"
78
+ authorization_signed_response_alg: parsedClientMeta.authorization_signed_response_alg
78
79
  }
79
80
  };
80
81
  }
@@ -83,7 +84,36 @@ var zJarmClientMetadataParsed = zJarmClientMetadata.transform((client_metadata)
83
84
 
84
85
  // src/models/z-vp-formats-supported.ts
85
86
  import { z as z2 } from "zod";
86
- var zVpFormatsSupported = z2.record(
87
+ var zVpFormatsSupported = z2.object({
88
+ "dc+sd-jwt": z2.optional(
89
+ z2.object({
90
+ "sd-jwt_alg_values": z2.optional(z2.array(z2.string()).nonempty()),
91
+ "kb-jwt_alg_values": z2.optional(z2.array(z2.string()).nonempty())
92
+ }).passthrough()
93
+ ),
94
+ jwt_vc_json: z2.optional(
95
+ z2.object({
96
+ alg_values: z2.optional(z2.array(z2.string()).nonempty())
97
+ }).passthrough()
98
+ ),
99
+ ldp_vc: z2.optional(
100
+ z2.object({
101
+ proof_type_values: z2.optional(z2.array(z2.string()).nonempty()),
102
+ cryptosuite_values: z2.optional(z2.array(z2.string()).nonempty())
103
+ }).passthrough()
104
+ ),
105
+ mso_mdoc: z2.optional(
106
+ z2.object({
107
+ // Draft 27
108
+ issuer_signed_alg_values: z2.optional(z2.array(z2.number()).nonempty()),
109
+ device_signed_alg_values: z2.optional(z2.array(z2.number()).nonempty()),
110
+ // Draft 28+
111
+ issuerauth_alg_values: z2.optional(z2.array(z2.number()).nonempty()),
112
+ deviceauth_alg_values: z2.optional(z2.array(z2.number()).nonempty())
113
+ }).passthrough()
114
+ )
115
+ }).passthrough().catchall(z2.object({}).passthrough());
116
+ var zLegacyVpFormats = z2.record(
87
117
  z2.string(),
88
118
  z2.object({
89
119
  alg_values_supported: z2.optional(z2.array(z2.string()))
@@ -95,7 +125,12 @@ var zClientMetadata = z3.object({
95
125
  // Up until draft 22
96
126
  jwks_uri: z3.string().url().optional(),
97
127
  jwks: z3.optional(zJwkSet),
98
- vp_formats: z3.optional(zVpFormatsSupported),
128
+ // Up until draft 26
129
+ vp_formats: z3.optional(zLegacyVpFormats),
130
+ // From draft 27
131
+ vp_formats_supported: z3.optional(zVpFormatsSupported),
132
+ // From draft 28
133
+ encrypted_response_enc_values_supported: z3.optional(z3.array(z3.string())),
99
134
  ...zJarmClientMetadata.shape,
100
135
  logo_uri: zHttpsUrl.optional(),
101
136
  client_name: z3.string().optional()
@@ -137,9 +172,11 @@ var zOpenid4vpAuthorizationRequest = z5.object({
137
172
  "did",
138
173
  "verifier_attestation",
139
174
  "x509_san_dns",
140
- "x509_san_uri"
175
+ "x509_san_uri",
176
+ "x509_hash"
141
177
  ]).optional(),
142
- verifier_attestations: zVerifierAttestations.optional()
178
+ verifier_attestations: zVerifierAttestations.optional(),
179
+ verifier_info: zVerifierAttestations.optional()
143
180
  }).passthrough();
144
181
  var zOpenid4vpAuthorizationRequestFromUriParams = z5.string().url().transform((url) => Object.fromEntries(new URL(url).searchParams)).pipe(
145
182
  z5.object({
@@ -147,7 +184,8 @@ var zOpenid4vpAuthorizationRequestFromUriParams = z5.string().url().transform((u
147
184
  client_metadata: zStringToJson.optional(),
148
185
  dcql_query: zStringToJson.optional(),
149
186
  transaction_data: zStringToJson.optional(),
150
- verifier_attestations: zStringToJson.optional()
187
+ verifier_attestations: zStringToJson.optional(),
188
+ verifier_info: zStringToJson.optional()
151
189
  }).passthrough()
152
190
  );
153
191
 
@@ -162,7 +200,8 @@ var zOpenid4vpAuthorizationRequestDcApi = zOpenid4vpAuthorizationRequest.pick({
162
200
  dcql_query: true,
163
201
  trust_chain: true,
164
202
  state: true,
165
- verifier_attestations: true
203
+ verifier_attestations: true,
204
+ verifier_info: true
166
205
  }).extend({
167
206
  client_id: z6.optional(z6.string()),
168
207
  expected_origins: z6.array(z6.string()).optional(),
@@ -179,31 +218,55 @@ function isOpenid4vpAuthorizationRequestDcApi(request) {
179
218
  return isOpenid4vpResponseModeDcApi(request.response_mode);
180
219
  }
181
220
 
182
- // src/client-identifier-scheme/z-client-id-scheme.ts
221
+ // src/client-identifier-prefix/z-client-id-prefix.ts
183
222
  import { getGlobalConfig } from "@openid4vc/utils";
184
223
  import { z as z7 } from "zod";
185
- var zClientIdScheme = z7.enum([
224
+ var zClientIdPrefix = z7.enum([
186
225
  "pre-registered",
187
226
  "redirect_uri",
188
- "https",
189
227
  "verifier_attestation",
228
+ "https",
229
+ // pre draft 26
230
+ "openid_federation",
231
+ // from draft 26
190
232
  "did",
191
- "x509_san_dns",
233
+ // pre draft 26
234
+ "decentralized_identifier",
235
+ // from draft 26
192
236
  "x509_san_uri",
237
+ // pre-draft 25
238
+ "x509_hash",
239
+ // from draft 25
240
+ "x509_san_dns",
241
+ "origin",
242
+ // from draft 25
193
243
  "web-origin"
244
+ // pre-draft 25
194
245
  ]);
195
- var zClientIdToClientIdScheme = z7.union(
246
+ var zUniformClientIdPrefix = zClientIdPrefix.exclude(["did", "https", "web-origin"]);
247
+ var zClientIdToClientIdPrefixAndIdentifier = z7.union(
196
248
  [
197
249
  z7.string({ message: "client_id MUST be a string" }).includes(":").transform((clientId) => {
198
- const clientIdScheme = clientId.split(":")[0];
199
- return clientIdScheme === "http" && getGlobalConfig().allowInsecureUrls ? "https" : clientIdScheme;
200
- }).pipe(zClientIdScheme.exclude(["pre-registered"])),
201
- z7.string().refine((clientId) => clientId.includes(":") === false).transform(() => "pre-registered")
250
+ const colonIndex = clientId.indexOf(":");
251
+ const clientIdPrefix = clientId.slice(0, colonIndex);
252
+ const clientIdIdentifier = clientId.slice(colonIndex + 1);
253
+ if (clientIdPrefix === "http" && getGlobalConfig().allowInsecureUrls) {
254
+ return ["https", clientId];
255
+ }
256
+ if (clientIdPrefix === "did" || clientIdPrefix === "http" || clientIdPrefix === "https") {
257
+ return [clientIdPrefix, clientId];
258
+ }
259
+ return [clientIdPrefix, clientIdIdentifier];
260
+ }).pipe(z7.tuple([zClientIdPrefix.exclude(["pre-registered"]), z7.string()])),
261
+ z7.string().refine((clientId) => clientId.includes(":") === false).transform((clientId) => ["pre-registered", clientId])
202
262
  ],
203
263
  {
204
- message: `client_id must either start with a known prefix followed by ':' or contain no ':'. Known prefixes are ${zClientIdScheme.exclude(["pre-registered"]).options.join(", ")}`
264
+ message: `client_id must either start with a known prefix followed by ':' or contain no ':'. Known prefixes are ${zClientIdPrefix.exclude(["pre-registered"]).options.join(", ")}`
205
265
  }
206
266
  );
267
+ var zClientIdPrefixToUniform = zClientIdPrefix.transform(
268
+ (prefix) => prefix === "did" ? "decentralized_identifier" : prefix === "https" ? "openid_federation" : prefix === "web-origin" ? "origin" : prefix
269
+ );
207
270
  var zLegacyClientIdScheme = z7.enum([
208
271
  "pre-registered",
209
272
  "redirect_uri",
@@ -213,10 +276,15 @@ var zLegacyClientIdScheme = z7.enum([
213
276
  "x509_san_dns",
214
277
  "x509_san_uri"
215
278
  ]);
216
- var zLegacyClientIdSchemeToClientIdScheme = zLegacyClientIdScheme.optional().default("pre-registered").transform((clientIdScheme) => clientIdScheme === "entity_id" ? "https" : clientIdScheme);
279
+ var zLegacyClientIdSchemeToClientIdPrefix = zLegacyClientIdScheme.optional().default("pre-registered").transform(
280
+ (clientIdScheme) => clientIdScheme === "entity_id" ? "openid_federation" : clientIdScheme === "did" ? "decentralized_identifier" : clientIdScheme
281
+ );
217
282
 
218
- // src/client-identifier-scheme/parse-client-identifier-scheme.ts
283
+ // src/client-identifier-prefix/parse-client-identifier-prefix.ts
219
284
  function getOpenid4vpClientId(options) {
285
+ const original = {
286
+ clientId: options.clientId
287
+ };
220
288
  if (isOpenid4vpResponseModeDcApi(options.responseMode)) {
221
289
  if (!options.clientId) {
222
290
  if (!options.origin) {
@@ -226,20 +294,37 @@ function getOpenid4vpClientId(options) {
226
294
  });
227
295
  }
228
296
  return {
229
- clientIdScheme: "web-origin",
230
- clientId: `web-origin:${options.origin}`
297
+ clientIdPrefix: "origin",
298
+ effectiveClientIdPrefix: "origin",
299
+ clientIdIdentifier: options.origin,
300
+ // FIXME: draft 24 uses web-origin, draft 25+ uses origin
301
+ // But it's not really possible to know which one to use as the
302
+ // 'effective' client id. Defaulting to origin: since that's newer
303
+ effectiveClientId: `origin:${options.origin}`,
304
+ original
231
305
  };
232
306
  }
233
- const parsedClientIdScheme2 = zClientIdToClientIdScheme.safeParse(options.clientId);
234
- if (!parsedClientIdScheme2.success) {
307
+ const parsedClientIdPrefixAndIdentifier2 = zClientIdToClientIdPrefixAndIdentifier.safeParse(options.clientId);
308
+ if (!parsedClientIdPrefixAndIdentifier2.success) {
309
+ throw new Oauth2ServerErrorResponseError({
310
+ error: Oauth2ErrorCodes.InvalidRequest,
311
+ error_description: `Failed to parse client identifier. Unsupported client_id '${options.clientId}'.`
312
+ });
313
+ }
314
+ const [clientIdScheme2, clientIdIdentifier2] = parsedClientIdPrefixAndIdentifier2.data;
315
+ const uniformClientIdScheme2 = zClientIdPrefixToUniform.safeParse(clientIdScheme2);
316
+ if (!uniformClientIdScheme2.success) {
235
317
  throw new Oauth2ServerErrorResponseError({
236
318
  error: Oauth2ErrorCodes.InvalidRequest,
237
319
  error_description: `Failed to parse client identifier. Unsupported client_id '${options.clientId}'.`
238
320
  });
239
321
  }
240
322
  return {
241
- clientId: options.clientId,
242
- clientIdScheme: parsedClientIdScheme2.data
323
+ effectiveClientId: options.clientId,
324
+ effectiveClientIdPrefix: clientIdScheme2,
325
+ original,
326
+ clientIdPrefix: uniformClientIdScheme2.data,
327
+ clientIdIdentifier: clientIdIdentifier2
243
328
  };
244
329
  }
245
330
  if (!options.clientId) {
@@ -249,62 +334,75 @@ function getOpenid4vpClientId(options) {
249
334
  });
250
335
  }
251
336
  if (options.legacyClientIdScheme) {
252
- const parsedClientIdScheme2 = zLegacyClientIdSchemeToClientIdScheme.safeParse(options.legacyClientIdScheme);
253
- if (!parsedClientIdScheme2.success) {
337
+ const parsedClientIdPrefix = zLegacyClientIdSchemeToClientIdPrefix.safeParse(options.legacyClientIdScheme);
338
+ if (!parsedClientIdPrefix.success) {
254
339
  throw new Oauth2ServerErrorResponseError({
255
340
  error: Oauth2ErrorCodes.InvalidRequest,
256
341
  error_description: `Failed to parse client identifier. Unsupported client_id_scheme value '${options.legacyClientIdScheme}'.`
257
342
  });
258
343
  }
259
- const clientIdScheme = parsedClientIdScheme2.data;
344
+ const clientIdPrefix = parsedClientIdPrefix.data;
260
345
  return {
261
- clientId: clientIdScheme === "https" || clientIdScheme === "did" || clientIdScheme === "pre-registered" ? options.clientId : `${parsedClientIdScheme2.data}:${options.clientId}`,
262
- clientIdScheme: parsedClientIdScheme2.data,
263
- legacyClientId: options.clientId
346
+ effectiveClientId: options.clientId,
347
+ clientIdIdentifier: options.clientId,
348
+ clientIdPrefix,
349
+ effectiveClientIdPrefix: options.legacyClientIdScheme ?? "pre-registered",
350
+ original: {
351
+ ...original,
352
+ clientIdScheme: options.legacyClientIdScheme
353
+ }
264
354
  };
265
355
  }
266
- const parsedClientIdScheme = zClientIdToClientIdScheme.safeParse(options.clientId);
267
- if (!parsedClientIdScheme.success) {
356
+ const parsedClientIdPrefixAndIdentifier = zClientIdToClientIdPrefixAndIdentifier.safeParse(options.clientId);
357
+ if (!parsedClientIdPrefixAndIdentifier.success) {
358
+ throw new Oauth2ServerErrorResponseError({
359
+ error: Oauth2ErrorCodes.InvalidRequest,
360
+ error_description: `Failed to parse client identifier. Unsupported client_id '${options.clientId}'.`
361
+ });
362
+ }
363
+ const [clientIdScheme, clientIdIdentifier] = parsedClientIdPrefixAndIdentifier.data;
364
+ const uniformClientIdScheme = zClientIdPrefixToUniform.safeParse(clientIdScheme);
365
+ if (!uniformClientIdScheme.success) {
268
366
  throw new Oauth2ServerErrorResponseError({
269
367
  error: Oauth2ErrorCodes.InvalidRequest,
270
368
  error_description: `Failed to parse client identifier. Unsupported client_id '${options.clientId}'.`
271
369
  });
272
370
  }
273
371
  return {
274
- clientId: options.clientId,
275
- clientIdScheme: parsedClientIdScheme.data
372
+ effectiveClientId: options.clientId,
373
+ clientIdPrefix: uniformClientIdScheme.data,
374
+ effectiveClientIdPrefix: clientIdScheme,
375
+ clientIdIdentifier,
376
+ original
276
377
  };
277
378
  }
278
- function validateOpenid4vpClientId(options, parserConfig) {
379
+ async function validateOpenid4vpClientId(options, parserConfig) {
279
380
  const { authorizationRequestPayload, jar, origin } = options;
280
381
  const parserConfigWithDefaults = {
281
- supportedSchemes: parserConfig?.supportedSchemes || Object.values(zClientIdScheme.options)
382
+ supportedSchemes: parserConfig?.supportedSchemes || Object.values(zClientIdPrefix.options)
282
383
  };
283
- const { clientId, legacyClientId, clientIdScheme } = getOpenid4vpClientId({
384
+ const { clientIdIdentifier, clientIdPrefix, effectiveClientId, original } = getOpenid4vpClientId({
284
385
  clientId: authorizationRequestPayload.client_id,
285
386
  legacyClientIdScheme: authorizationRequestPayload.client_id_scheme,
286
387
  responseMode: authorizationRequestPayload.response_mode,
287
388
  origin
288
389
  });
289
- if (clientIdScheme === "pre-registered") {
390
+ if (clientIdPrefix === "pre-registered") {
290
391
  return {
291
- scheme: "pre-registered",
292
- identifier: clientId,
293
- originalValue: clientId,
294
- legacyClientId,
295
- clientMetadata: authorizationRequestPayload.client_metadata
392
+ prefix: "pre-registered",
393
+ identifier: clientIdIdentifier,
394
+ effective: effectiveClientId,
395
+ original
296
396
  };
297
397
  }
298
- const colonIndex = clientId.indexOf(":");
299
- const identifierPart = clientId.substring(colonIndex + 1);
300
- if (!parserConfigWithDefaults.supportedSchemes.includes(clientIdScheme)) {
398
+ if (!parserConfigWithDefaults.supportedSchemes.includes(clientIdPrefix)) {
301
399
  throw new Oauth2ServerErrorResponseError({
302
400
  error: Oauth2ErrorCodes.InvalidRequest,
303
- error_description: `Unsupported client identifier scheme. ${clientIdScheme} is not supported.`
401
+ error_description: `Unsupported client identifier scheme. ${clientIdPrefix} is not supported.`
304
402
  });
305
403
  }
306
- if (clientIdScheme === "https") {
307
- if (!zHttpsUrl3.safeParse(clientId).success) {
404
+ if (clientIdPrefix === "openid_federation") {
405
+ if (!zHttpsUrl3.safeParse(clientIdIdentifier).success) {
308
406
  throw new Oauth2ServerErrorResponseError(
309
407
  {
310
408
  error: Oauth2ErrorCodes.InvalidRequest,
@@ -328,14 +426,14 @@ function validateOpenid4vpClientId(options, parserConfig) {
328
426
  });
329
427
  }
330
428
  return {
331
- scheme: clientIdScheme,
332
- identifier: clientId,
333
- originalValue: clientId,
334
- legacyClientId,
429
+ prefix: "openid_federation",
430
+ identifier: clientIdIdentifier,
431
+ effective: effectiveClientId,
432
+ original,
335
433
  trustChain: authorizationRequestPayload.trust_chain
336
434
  };
337
435
  }
338
- if (clientIdScheme === "redirect_uri") {
436
+ if (clientIdPrefix === "redirect_uri") {
339
437
  if (jar) {
340
438
  throw new Oauth2ServerErrorResponseError({
341
439
  error: Oauth2ErrorCodes.InvalidRequest,
@@ -349,14 +447,15 @@ function validateOpenid4vpClientId(options, parserConfig) {
349
447
  });
350
448
  }
351
449
  return {
352
- scheme: clientIdScheme,
353
- identifier: identifierPart,
354
- originalValue: clientId,
355
- legacyClientId,
450
+ prefix: clientIdPrefix,
451
+ identifier: clientIdIdentifier,
452
+ effective: effectiveClientId,
453
+ original,
454
+ clientMetadata: authorizationRequestPayload.client_metadata,
356
455
  redirectUri: authorizationRequestPayload.redirect_uri ?? authorizationRequestPayload.response_uri
357
456
  };
358
457
  }
359
- if (clientIdScheme === "did") {
458
+ if (clientIdPrefix === "decentralized_identifier") {
360
459
  if (!jar) {
361
460
  throw new Oauth2ServerErrorResponseError({
362
461
  error: Oauth2ErrorCodes.InvalidRequest,
@@ -369,113 +468,115 @@ function validateOpenid4vpClientId(options, parserConfig) {
369
468
  error_description: "Something went wrong. The JWT signer method is not did but the client identifier scheme is did."
370
469
  });
371
470
  }
372
- if (!clientId.startsWith("did:")) {
471
+ if (!clientIdIdentifier.startsWith("did:")) {
373
472
  throw new Oauth2ServerErrorResponseError({
374
473
  error: Oauth2ErrorCodes.InvalidRequest,
375
- error_description: "Invalid client identifier. Client identifier must start with 'did:'"
474
+ error_description: "Invalid client identifier. Client id identifier must start with 'did:'"
376
475
  });
377
476
  }
378
477
  const [did] = jar.signer.didUrl.split("#");
379
- if (clientId !== did) {
478
+ if (clientIdIdentifier !== did) {
380
479
  throw new Oauth2ServerErrorResponseError({
381
480
  error: Oauth2ErrorCodes.InvalidRequest,
382
- error_description: 'With client identifier scheme "did" the JAR request must be signed by the same DID as the client identifier.'
481
+ error_description: `With client identifier scheme '${clientIdPrefix}' the JAR request must be signed by the same DID as the client identifier.`
383
482
  });
384
483
  }
385
484
  return {
386
- scheme: clientIdScheme,
387
- identifier: clientId,
388
- originalValue: clientId,
389
- legacyClientId,
485
+ prefix: "decentralized_identifier",
486
+ identifier: clientIdIdentifier,
487
+ effective: effectiveClientId,
488
+ original,
489
+ clientMetadata: authorizationRequestPayload.client_metadata,
390
490
  didUrl: jar.signer.didUrl
391
491
  };
392
492
  }
393
- if (clientIdScheme === "x509_san_dns" || clientIdScheme === "x509_san_uri") {
493
+ if (clientIdPrefix === "x509_san_dns" || clientIdPrefix === "x509_san_uri" || clientIdPrefix === "x509_hash") {
394
494
  if (!jar) {
395
495
  throw new Oauth2ServerErrorResponseError({
396
496
  error: Oauth2ErrorCodes.InvalidRequest,
397
- error_description: 'Using client identifier scheme "x509_san_dns" or "x509_san_uri" requires a signed JAR request.'
497
+ error_description: `Using client identifier scheme '${clientIdPrefix}' requires a signed JAR request.`
398
498
  });
399
499
  }
400
500
  if (jar.signer.method !== "x5c") {
401
501
  throw new Oauth2ServerErrorResponseError({
402
502
  error: Oauth2ErrorCodes.InvalidRequest,
403
- error_description: "Something went wrong. The JWT signer method is not x5c but the client identifier scheme is x509_san_dns."
503
+ error_description: `Something went wrong. The JWT signer method is not x5c but the client identifier scheme is '${clientIdPrefix}'`
404
504
  });
405
505
  }
406
- if (clientIdScheme === "x509_san_dns") {
407
- if (!options.callbacks.getX509CertificateMetadata) {
408
- throw new Oauth2ServerErrorResponseError(
409
- {
410
- error: Oauth2ErrorCodes.ServerError
411
- },
412
- {
413
- internalMessage: "Missing required 'getX509CertificateMetadata' callback for verification of 'x509_san_dns' client id scheme"
414
- }
415
- );
416
- }
506
+ if (!options.callbacks.getX509CertificateMetadata) {
507
+ throw new Oauth2ServerErrorResponseError(
508
+ {
509
+ error: Oauth2ErrorCodes.ServerError
510
+ },
511
+ {
512
+ internalMessage: `Missing required 'getX509CertificateMetadata' callback for verification of '${clientIdPrefix}' client id scheme`
513
+ }
514
+ );
515
+ }
516
+ if (clientIdPrefix === "x509_san_dns") {
417
517
  const { sanDnsNames } = options.callbacks.getX509CertificateMetadata(jar.signer.x5c[0]);
418
- if (!sanDnsNames.includes(identifierPart)) {
518
+ if (!sanDnsNames.includes(clientIdIdentifier)) {
419
519
  throw new Oauth2ServerErrorResponseError({
420
520
  error: Oauth2ErrorCodes.InvalidRequest,
421
- error_description: `Invalid client identifier. One of the leaf certificates san dns names [${sanDnsNames.join(", ")}] must match the client identifier '${identifierPart}'. `
521
+ error_description: `Invalid client identifier. One of the leaf certificates san dns names [${sanDnsNames.join(", ")}] must match the client identifier '${clientIdIdentifier}'. `
422
522
  });
423
523
  }
424
524
  if (!isOpenid4vpAuthorizationRequestDcApi(authorizationRequestPayload)) {
425
525
  const uri = authorizationRequestPayload.redirect_uri ?? authorizationRequestPayload.response_uri;
426
- if (!uri || new URL2(uri).hostname !== identifierPart) {
526
+ if (!uri || new URL2(uri).hostname !== clientIdIdentifier) {
427
527
  throw new Oauth2ServerErrorResponseError({
428
528
  error: Oauth2ErrorCodes.InvalidRequest,
429
529
  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."
430
530
  });
431
531
  }
432
532
  }
433
- } else if (clientIdScheme === "x509_san_uri") {
434
- if (!options.callbacks.getX509CertificateMetadata) {
435
- throw new Oauth2ServerErrorResponseError(
436
- {
437
- error: Oauth2ErrorCodes.ServerError
438
- },
439
- {
440
- internalMessage: "Missing required 'getX509CertificateMetadata' callback for verification of 'x509_san_uri' client id scheme"
441
- }
442
- );
443
- }
533
+ } else if (clientIdPrefix === "x509_san_uri") {
444
534
  const { sanUriNames } = options.callbacks.getX509CertificateMetadata(jar.signer.x5c[0]);
445
- if (!sanUriNames.includes(identifierPart)) {
535
+ if (!sanUriNames.includes(clientIdIdentifier)) {
446
536
  throw new Oauth2ServerErrorResponseError({
447
537
  error: Oauth2ErrorCodes.InvalidRequest,
448
- error_description: `Invalid client identifier. One of the leaf certificates san uri names [${sanUriNames.join(", ")}] must match the client identifier '${identifierPart}'.`
538
+ error_description: `Invalid client identifier. One of the leaf certificates san uri names [${sanUriNames.join(", ")}] must match the client identifier '${clientIdIdentifier}'.`
449
539
  });
450
540
  }
451
541
  if (!isOpenid4vpAuthorizationRequestDcApi(authorizationRequestPayload)) {
452
542
  const uri = authorizationRequestPayload.redirect_uri || authorizationRequestPayload.response_uri;
453
- if (!uri || uri !== identifierPart) {
543
+ if (!uri || uri !== clientIdIdentifier) {
454
544
  throw new Oauth2ServerErrorResponseError({
455
545
  error: Oauth2ErrorCodes.InvalidRequest,
456
546
  error_description: "The redirect_uri value MUST match the Client Identifier without the prefix x509_san_uri"
457
547
  });
458
548
  }
459
549
  }
550
+ } else if (clientIdPrefix === "x509_hash") {
551
+ const x509Hash = encodeToBase64Url(
552
+ await options.callbacks.hash(decodeBase64(jar.signer.x5c[0]), HashAlgorithm.Sha256)
553
+ );
554
+ if (x509Hash !== clientIdIdentifier) {
555
+ throw new Oauth2ServerErrorResponseError({
556
+ error: Oauth2ErrorCodes.InvalidRequest,
557
+ error_description: `Invalid client identifier. Expected the base64url encoded sha-256 hash of the leaf x5c certificate ('${x509Hash}') to match the client identifier '${clientIdIdentifier}'.`
558
+ });
559
+ }
460
560
  }
461
561
  return {
462
- scheme: clientIdScheme,
463
- identifier: identifierPart,
464
- originalValue: clientId,
465
- legacyClientId,
466
- x5c: jar.signer.x5c
562
+ prefix: clientIdPrefix,
563
+ identifier: clientIdIdentifier,
564
+ effective: effectiveClientId,
565
+ original,
566
+ x5c: jar.signer.x5c,
567
+ clientMetadata: authorizationRequestPayload.client_metadata
467
568
  };
468
569
  }
469
- if (clientIdScheme === "web-origin") {
570
+ if (clientIdPrefix === "origin") {
470
571
  return {
471
- scheme: clientIdScheme,
472
- identifier: identifierPart,
473
- originalValue: clientId,
474
- legacyClientId,
572
+ prefix: clientIdPrefix,
573
+ identifier: clientIdIdentifier,
574
+ effective: effectiveClientId,
575
+ original,
475
576
  clientMetadata: authorizationRequestPayload.client_metadata
476
577
  };
477
578
  }
478
- if (clientIdScheme === "verifier_attestation") {
579
+ if (clientIdPrefix === "verifier_attestation") {
479
580
  if (!jar) {
480
581
  throw new Oauth2ServerErrorResponseError({
481
582
  error: Oauth2ErrorCodes.InvalidRequest,
@@ -484,10 +585,11 @@ function validateOpenid4vpClientId(options, parserConfig) {
484
585
  }
485
586
  }
486
587
  return {
487
- scheme: clientIdScheme,
488
- identifier: identifierPart,
489
- legacyClientId,
490
- originalValue: clientId
588
+ prefix: clientIdPrefix,
589
+ clientMetadata: authorizationRequestPayload.client_metadata,
590
+ identifier: clientIdIdentifier,
591
+ effective: effectiveClientId,
592
+ original
491
593
  };
492
594
  }
493
595
 
@@ -495,6 +597,7 @@ function validateOpenid4vpClientId(options, parserConfig) {
495
597
  import {
496
598
  Oauth2Error as Oauth2Error3,
497
599
  decodeJwt,
600
+ decodeJwtHeader,
498
601
  jwtSignerFromJwt,
499
602
  zCompactJwe,
500
603
  zCompactJwt,
@@ -503,15 +606,18 @@ import {
503
606
  import z9 from "zod";
504
607
 
505
608
  // src/jarm/jarm-extract-jwks.ts
506
- function extractJwksFromClientMetadata(clientMetadata) {
507
- const parsed = zJarmClientMetadataParsed.parse(clientMetadata);
508
- const encryptionAlg = parsed.client_metadata.authorization_encrypted_response_enc;
509
- const signingAlg = parsed.client_metadata.authorization_signed_response_alg;
510
- const encJwk = clientMetadata.jwks.keys.find((key) => key.use === "enc" && key.alg === encryptionAlg) ?? clientMetadata.jwks.keys.find((key) => key.use === "enc") ?? // fallback, take first key. HAIP does not specify requirement on enc
511
- clientMetadata.jwks.keys?.[0];
512
- const sigJwk = clientMetadata.jwks.keys.find((key) => key.use === "sig" && key.alg === signingAlg) ?? clientMetadata.jwks.keys.find((key) => key.use === "sig") ?? // falback, take first key
513
- clientMetadata.jwks.keys?.[0];
514
- return { encJwk, sigJwk };
609
+ function extractJwkFromJwks(jwks, {
610
+ kid,
611
+ supportedAlgValues
612
+ }) {
613
+ if (kid) {
614
+ return jwks.keys.find((jwk) => jwk.kid === kid);
615
+ }
616
+ let algFiltered = jwks.keys.filter((key) => key.alg && supportedAlgValues?.includes(key.alg));
617
+ if (algFiltered.length === 0) algFiltered = jwks.keys;
618
+ let encFiltered = algFiltered.filter((key) => key.use === "enc");
619
+ if (!encFiltered) encFiltered = algFiltered.filter((key) => key.use !== "sig");
620
+ return encFiltered.length > 0 ? encFiltered[0] : jwks.keys[0];
515
621
  }
516
622
 
517
623
  // src/jarm/jarm-authorization-response/jarm-validate-authorization-response.ts
@@ -562,10 +668,18 @@ var JarmMode = /* @__PURE__ */ ((JarmMode2) => {
562
668
  })(JarmMode || {});
563
669
  var decryptJarmAuthorizationResponseJwt = async (options) => {
564
670
  const { jarmAuthorizationResponseJwt, callbacks, authorizationRequestPayload } = options;
565
- const encryptionJwk = authorizationRequestPayload.client_metadata?.jwks ? extractJwksFromClientMetadata({
566
- ...authorizationRequestPayload.client_metadata,
567
- jwks: authorizationRequestPayload.client_metadata.jwks
568
- }).encJwk : void 0;
671
+ let encryptionJwk = void 0;
672
+ const { header } = decodeJwtHeader({
673
+ jwt: jarmAuthorizationResponseJwt
674
+ });
675
+ if (authorizationRequestPayload.client_metadata?.jwks) {
676
+ encryptionJwk = extractJwkFromJwks(authorizationRequestPayload.client_metadata.jwks, {
677
+ // Kid always take precedence
678
+ kid: header.kid,
679
+ // This value was removed in draft 26, but if it's still provided, we can use it to determine the key to use
680
+ supportedAlgValues: authorizationRequestPayload.client_metadata.authorization_encrypted_response_alg ? [authorizationRequestPayload.client_metadata.authorization_encrypted_response_alg] : void 0
681
+ });
682
+ }
569
683
  const result = await callbacks.decryptJwe(jarmAuthorizationResponseJwt, { jwk: encryptionJwk });
570
684
  if (!result.decrypted) {
571
685
  throw new Oauth2Error3("Failed to decrypt jarm auth response.");
@@ -703,10 +817,10 @@ var validateOpenid4vpAuthorizationRequestPayload = (options) => {
703
817
  error_description: 'The "wallet_nonce" parameter MUST match the "expectedNonce" parameter when the "expectedNonce" parameter is provided.'
704
818
  });
705
819
  }
706
- if (params.client_id.startsWith("web-origin:")) {
820
+ if (params.client_id.startsWith("web-origin:") || params.client_id.startsWith("origin:")) {
707
821
  throw new Oauth2ServerErrorResponseError2({
708
822
  error: Oauth2ErrorCodes2.InvalidRequest,
709
- 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}`
823
+ error_description: `The 'client_id' parameter MUST NOT use client identifier scheme '${params.client_id.split(":")[0]}' when not using the dc_api response mode. Current: ${params.client_id}`
710
824
  });
711
825
  }
712
826
  };
@@ -942,6 +1056,48 @@ import z13 from "zod";
942
1056
  import { Oauth2ErrorCodes as Oauth2ErrorCodes5, Oauth2ServerErrorResponseError as Oauth2ServerErrorResponseError6 } from "@openid4vc/oauth2";
943
1057
  function parseAuthorizationRequestVersion(request) {
944
1058
  const requirements = [];
1059
+ if (request.verifier_info) {
1060
+ requirements.push([">=", 29]);
1061
+ }
1062
+ if (request.verifier_attestations) {
1063
+ requirements.push(["<", 29]);
1064
+ }
1065
+ if (request.client_metadata?.vp_formats_supported?.mso_mdoc?.deviceauth_alg_values || request.client_metadata?.vp_formats_supported?.mso_mdoc?.deviceauth_alg_values) {
1066
+ requirements.push([">=", 28]);
1067
+ }
1068
+ if (request.client_metadata?.vp_formats_supported?.mso_mdoc?.issuer_signed_alg_values || request.client_metadata?.vp_formats_supported?.mso_mdoc?.device_signed_alg_values) {
1069
+ requirements.push(["<", 28]);
1070
+ }
1071
+ if (request.client_metadata?.vp_formats) {
1072
+ requirements.push([">=", 27]);
1073
+ }
1074
+ if (request.client_metadata?.vp_formats_supported) {
1075
+ requirements.push(["<", 27]);
1076
+ }
1077
+ if (request.client_id?.startsWith("openid_federation:") || request.client_id?.startsWith("decentralized_identifier:")) {
1078
+ requirements.push([">=", 26]);
1079
+ }
1080
+ if (request.client_id?.startsWith("did:")) {
1081
+ requirements.push(["<", 26]);
1082
+ }
1083
+ if (request.presentation_definition || request.presentation_definition_uri) {
1084
+ requirements.push([">=", 26]);
1085
+ }
1086
+ if (request.verifier_attestations) {
1087
+ requirements.push([">=", 26]);
1088
+ }
1089
+ if (request.client_id?.startsWith("x509_san_uri:")) {
1090
+ requirements.push(["<", 25]);
1091
+ }
1092
+ if (request.client_id?.startsWith("x509_hash:")) {
1093
+ requirements.push([">=", 25]);
1094
+ }
1095
+ if (request.client_id?.startsWith("web-origin:")) {
1096
+ requirements.push(["<", 25]);
1097
+ }
1098
+ if (request.client_id?.startsWith("origin:")) {
1099
+ requirements.push([">=", 25]);
1100
+ }
945
1101
  if (isOpenid4vpAuthorizationRequestDcApi(request) && (request.response_mode === "w3c_dc_api" || request.response_mode === "w3c_dc_api.jwt")) {
946
1102
  requirements.push(["<", 23]);
947
1103
  requirements.push([">=", 21]);
@@ -961,7 +1117,7 @@ function parseAuthorizationRequestVersion(request) {
961
1117
  if (request.client_id) {
962
1118
  const colonIndex = request.client_id.indexOf(":");
963
1119
  const schemePart = request.client_id.substring(0, colonIndex);
964
- const parsedScheme = zClientIdScheme.safeParse(schemePart);
1120
+ const parsedScheme = zClientIdPrefix.safeParse(schemePart);
965
1121
  if (parsedScheme.success && parsedScheme.data !== "did" && parsedScheme.data !== "https") {
966
1122
  requirements.push([">=", 22]);
967
1123
  }
@@ -969,6 +1125,9 @@ function parseAuthorizationRequestVersion(request) {
969
1125
  if (!request.client_id) {
970
1126
  requirements.push([">=", 21]);
971
1127
  }
1128
+ if (request.dcql_query) {
1129
+ requirements.push([">=", 21]);
1130
+ }
972
1131
  if (request.client_metadata_uri) {
973
1132
  requirements.push(["<", 21]);
974
1133
  }
@@ -986,7 +1145,7 @@ function parseAuthorizationRequestVersion(request) {
986
1145
  }
987
1146
  const lessThanVersions = requirements.filter(([operator]) => operator === "<").map(([_, version]) => version);
988
1147
  const greaterThanVersions = requirements.filter(([operator]) => operator === ">=").map(([_, version]) => version);
989
- const highestPossibleVersion = lessThanVersions.length > 0 ? Math.max(Math.min(...lessThanVersions) - 1, 18) : 24;
1148
+ const highestPossibleVersion = lessThanVersions.length > 0 ? Math.max(Math.min(...lessThanVersions) - 1, 18) : 29;
990
1149
  const lowestRequiredVersion = greaterThanVersions.length > 0 ? Math.max(...greaterThanVersions) : 18;
991
1150
  if (lowestRequiredVersion > highestPossibleVersion) {
992
1151
  throw new Oauth2ServerErrorResponseError6({
@@ -1044,7 +1203,7 @@ async function verifyJarRequest(options) {
1044
1203
  const { callbacks, wallet = {} } = options;
1045
1204
  const jarRequestParams = validateJarRequestParams(options);
1046
1205
  const sendBy = jarRequestParams.request ? "value" : "reference";
1047
- const clientIdentifierScheme = jarRequestParams.client_id ? zClientIdScheme.safeParse(jarRequestParams.client_id.split(":")[0]).data : "web-origin";
1206
+ const clientIdentifierScheme = jarRequestParams.client_id ? zClientIdPrefix.safeParse(jarRequestParams.client_id.split(":")[0]).data : "origin";
1048
1207
  const method = jarRequestParams.request_uri_method ?? "get";
1049
1208
  if (method !== "get" && method !== "post") {
1050
1209
  throw new Oauth2ServerErrorResponseError8({
@@ -1120,15 +1279,15 @@ async function verifyJarRequestObject(options) {
1120
1279
  const { decryptedRequestObject, callbacks } = options;
1121
1280
  const jwt = decodeJwt3({ jwt: decryptedRequestObject, payloadSchema: zJarRequestObjectPayload });
1122
1281
  let jwtSigner;
1123
- const { clientIdScheme } = getOpenid4vpClientId({
1282
+ const { clientIdPrefix } = getOpenid4vpClientId({
1124
1283
  responseMode: jwt.payload.response_mode,
1125
1284
  clientId: jwt.payload.client_id,
1126
1285
  legacyClientIdScheme: jwt.payload.client_id_scheme
1127
1286
  });
1128
1287
  const clientIdToSignerMethod = {
1129
- did: ["did"],
1288
+ decentralized_identifier: ["did"],
1130
1289
  "pre-registered": ["custom", "did", "jwk"],
1131
- "web-origin": [],
1290
+ origin: [],
1132
1291
  // no signing allowed
1133
1292
  redirect_uri: [],
1134
1293
  // no signing allowed
@@ -1136,10 +1295,11 @@ async function verifyJarRequestObject(options) {
1136
1295
  verifier_attestation: ["did", "federation", "jwk", "x5c", "custom"],
1137
1296
  x509_san_dns: ["x5c"],
1138
1297
  x509_san_uri: ["x5c"],
1298
+ x509_hash: ["x5c"],
1139
1299
  // Handled separately
1140
- https: []
1300
+ openid_federation: []
1141
1301
  };
1142
- if (clientIdScheme === "https") {
1302
+ if (clientIdPrefix === "openid_federation") {
1143
1303
  if (!jwt.header.kid) {
1144
1304
  throw new Oauth2Error5(
1145
1305
  `When OpenID Federation is used for signed authorization request, the 'kid' parameter is required.`
@@ -1152,7 +1312,7 @@ async function verifyJarRequestObject(options) {
1152
1312
  kid: jwt.header.kid
1153
1313
  };
1154
1314
  } else {
1155
- jwtSigner = jwtSignerFromJwt2({ ...jwt, allowedSignerMethods: clientIdToSignerMethod[clientIdScheme] });
1315
+ jwtSigner = jwtSignerFromJwt2({ ...jwt, allowedSignerMethods: clientIdToSignerMethod[clientIdPrefix] });
1156
1316
  }
1157
1317
  const { signer } = await verifyJwt({
1158
1318
  verifyJwtCallback: callbacks.verifyJwt,
@@ -1177,7 +1337,7 @@ async function verifyJarRequestObject(options) {
1177
1337
 
1178
1338
  // src/transaction-data/parse-transaction-data.ts
1179
1339
  import { Oauth2ErrorCodes as Oauth2ErrorCodes8, Oauth2ServerErrorResponseError as Oauth2ServerErrorResponseError9 } from "@openid4vc/oauth2";
1180
- import { decodeBase64, encodeToUtf8String, parseIfJson } from "@openid4vc/utils";
1340
+ import { decodeBase64 as decodeBase642, encodeToUtf8String, parseIfJson } from "@openid4vc/utils";
1181
1341
 
1182
1342
  // src/transaction-data/z-transaction-data.ts
1183
1343
  import { z as z14 } from "zod";
@@ -1191,7 +1351,7 @@ var zTransactionData = z14.array(zTransactionEntry);
1191
1351
  // src/transaction-data/parse-transaction-data.ts
1192
1352
  function parseTransactionData(options) {
1193
1353
  const { transactionData } = options;
1194
- const decoded = transactionData.map((tdEntry) => parseIfJson(encodeToUtf8String(decodeBase64(tdEntry))));
1354
+ const decoded = transactionData.map((tdEntry) => parseIfJson(encodeToUtf8String(decodeBase642(tdEntry))));
1195
1355
  const parsedResult = zTransactionData.safeParse(decoded);
1196
1356
  if (!parsedResult.success) {
1197
1357
  throw new Oauth2ServerErrorResponseError9({
@@ -1243,7 +1403,7 @@ async function resolveOpenid4vpAuthorizationRequest(options) {
1243
1403
  if (!isOpenid4vpAuthorizationRequestDcApi(authorizationRequestPayload) && !clientMetadata && authorizationRequestPayload.client_metadata_uri) {
1244
1404
  clientMetadata = await fetchClientMetadata({ clientMetadataUri: authorizationRequestPayload.client_metadata_uri });
1245
1405
  }
1246
- const clientMeta = validateOpenid4vpClientId({
1406
+ const clientMeta = await validateOpenid4vpClientId({
1247
1407
  authorizationRequestPayload: {
1248
1408
  ...authorizationRequestPayload,
1249
1409
  client_metadata: clientMetadata
@@ -1276,7 +1436,8 @@ async function resolveOpenid4vpAuthorizationRequest(options) {
1276
1436
  jar,
1277
1437
  client: clientMeta,
1278
1438
  pex,
1279
- dcql
1439
+ dcql,
1440
+ version: parseAuthorizationRequestVersion(authorizationRequestPayload)
1280
1441
  };
1281
1442
  }
1282
1443
  function validateOpenId4vpAuthorizationRequestPayload(options) {
@@ -1304,7 +1465,7 @@ import {
1304
1465
  Oauth2ServerErrorResponseError as Oauth2ServerErrorResponseError11,
1305
1466
  fetchJwks
1306
1467
  } from "@openid4vc/oauth2";
1307
- import { dateToSeconds as dateToSeconds3, encodeToBase64Url } from "@openid4vc/utils";
1468
+ import { dateToSeconds as dateToSeconds3, encodeToBase64Url as encodeToBase64Url2 } from "@openid4vc/utils";
1308
1469
 
1309
1470
  // ../utils/src/date.ts
1310
1471
  function addSecondsToDate2(date, seconds) {
@@ -1401,7 +1562,7 @@ async function createOpenid4vpAuthorizationResponse(options) {
1401
1562
  ...options.authorizationResponsePayload,
1402
1563
  state: authorizationRequestPayload.state
1403
1564
  };
1404
- const { clientIdScheme } = getOpenid4vpClientId({
1565
+ const { clientIdPrefix } = getOpenid4vpClientId({
1405
1566
  responseMode: authorizationRequestPayload.response_mode,
1406
1567
  clientId: authorizationRequestPayload.client_id,
1407
1568
  legacyClientIdScheme: authorizationRequestPayload.client_id_scheme,
@@ -1417,9 +1578,9 @@ async function createOpenid4vpAuthorizationResponse(options) {
1417
1578
  authorizationResponsePayload
1418
1579
  };
1419
1580
  }
1420
- if (clientIdScheme === "https" && !options.clientMetadata) {
1581
+ if (clientIdPrefix === "openid_federation" && !options.clientMetadata) {
1421
1582
  throw new Oauth2Error8(
1422
- "When OpenID Federation is used as the client id scheme (https), passing externally fetched and verified 'clientMetadata' to the 'createOpenid4vpAuthorizationResponse' is required."
1583
+ "When OpenID Federation is used as the client id scheme (https/openid_federation), passing externally fetched and verified 'clientMetadata' to the 'createOpenid4vpAuthorizationResponse' is required."
1423
1584
  );
1424
1585
  }
1425
1586
  const clientMetadata = options.clientMetadata ?? authorizationRequestPayload.client_metadata;
@@ -1437,20 +1598,40 @@ async function createOpenid4vpAuthorizationResponse(options) {
1437
1598
  error_description: `Missing 'jwks' or 'jwks_uri' in client metadata. Cannot extract encryption JWK.`
1438
1599
  });
1439
1600
  }
1440
- const supportedJarmMetadata = jarmAssertMetadataSupported({
1441
- clientMetadata,
1442
- serverMetadata: jarm.serverMetadata
1443
- });
1444
- const clientMetaJwks = extractJwksFromClientMetadata({
1445
- ...clientMetadata,
1446
- jwks
1601
+ if (clientMetadata.authorization_encrypted_response_alg || clientMetadata.authorization_encrypted_response_env || clientMetadata.authorization_signed_response_alg) {
1602
+ jarmAssertMetadataSupported({
1603
+ clientMetadata,
1604
+ serverMetadata: jarm.serverMetadata
1605
+ });
1606
+ }
1607
+ const encJwk = extractJwkFromJwks(jwks, {
1608
+ supportedAlgValues: jarm.serverMetadata.authorization_encryption_alg_values_supported ?? (clientMetadata.authorization_encrypted_response_alg ? [clientMetadata.authorization_encrypted_response_alg] : void 0)
1447
1609
  });
1448
- if (!clientMetaJwks?.encJwk) {
1610
+ if (!encJwk) {
1449
1611
  throw new Oauth2ServerErrorResponseError11({
1450
1612
  error: Oauth2ErrorCodes10.InvalidRequest,
1451
1613
  error_description: "Could not extract encryption JWK from client metadata. Failed to create JARM response."
1452
1614
  });
1453
1615
  }
1616
+ let enc;
1617
+ if (clientMetadata.encrypted_response_enc_values_supported) {
1618
+ enc = jarm.serverMetadata.authorization_encryption_enc_values_supported.find(
1619
+ (enc2) => clientMetadata.encrypted_response_enc_values_supported?.includes(enc2)
1620
+ ) ?? clientMetadata.encrypted_response_enc_values_supported[0];
1621
+ } else {
1622
+ enc = clientMetadata.authorization_encrypted_response_enc ?? "A128GCM";
1623
+ }
1624
+ assertValueSupported({
1625
+ actual: enc,
1626
+ supported: jarm.serverMetadata.authorization_encryption_enc_values_supported,
1627
+ errorMessage: `Invalid 'enc' value ${enc}. Supported values are ${jarm.serverMetadata.authorization_encryption_enc_values_supported.join(", ")}`
1628
+ });
1629
+ const alg = encJwk.alg ?? clientMetadata.authorization_encrypted_response_alg ?? "ECDH-ES";
1630
+ assertValueSupported({
1631
+ actual: alg,
1632
+ supported: jarm.serverMetadata.authorization_encryption_alg_values_supported,
1633
+ errorMessage: `Invalid 'alg' value ${alg}. Supported values are ${jarm.serverMetadata.authorization_encryption_alg_values_supported.join(", ")}`
1634
+ });
1454
1635
  let additionalJwtPayload;
1455
1636
  if (jarm?.jwtSigner) {
1456
1637
  if (!jarm.authorizationServer) {
@@ -1479,13 +1660,13 @@ async function createOpenid4vpAuthorizationResponse(options) {
1479
1660
  const result = await createJarmAuthorizationResponse({
1480
1661
  jarmAuthorizationResponse: jarmResponsePayload,
1481
1662
  jwtSigner: jarm?.jwtSigner,
1482
- jweEncryptor: jarm?.encryption && (supportedJarmMetadata.type === "encrypt" || supportedJarmMetadata.type === "sign_encrypt") ? {
1663
+ jweEncryptor: jarm?.encryption ? {
1483
1664
  method: "jwk",
1484
- publicJwk: clientMetaJwks.encJwk,
1485
- apu: jarm.encryption.nonce ? encodeToBase64Url(jarm.encryption.nonce) : void 0,
1486
- apv: encodeToBase64Url(authorizationRequestPayload.nonce),
1487
- alg: supportedJarmMetadata.client_metadata.authorization_encrypted_response_alg,
1488
- enc: supportedJarmMetadata.client_metadata.authorization_encrypted_response_enc
1665
+ publicJwk: encJwk,
1666
+ apu: jarm.encryption.nonce ? encodeToBase64Url2(jarm.encryption.nonce) : void 0,
1667
+ apv: encodeToBase64Url2(authorizationRequestPayload.nonce),
1668
+ alg,
1669
+ enc
1489
1670
  } : void 0,
1490
1671
  callbacks: {
1491
1672
  signJwt: callbacks.signJwt,
@@ -1678,7 +1859,7 @@ function parseOpenid4VpAuthorizationResponsePayload(payload) {
1678
1859
  }
1679
1860
 
1680
1861
  // src/authorization-response/parse-jarm-authorization-response.ts
1681
- import { Oauth2Error as Oauth2Error12, decodeJwtHeader, zCompactJwe as zCompactJwe3, zCompactJwt as zCompactJwt3 } from "@openid4vc/oauth2";
1862
+ import { Oauth2Error as Oauth2Error12, decodeJwtHeader as decodeJwtHeader2, zCompactJwe as zCompactJwe3, zCompactJwt as zCompactJwt3 } from "@openid4vc/oauth2";
1682
1863
  import { parseWithErrorHandling as parseWithErrorHandling7 } from "@openid4vc/utils";
1683
1864
  import z20 from "zod";
1684
1865
  async function parseJarmAuthorizationResponse(options) {
@@ -1694,7 +1875,7 @@ async function parseJarmAuthorizationResponse(options) {
1694
1875
  expectedClientId,
1695
1876
  authorizationRequestPayload
1696
1877
  });
1697
- const { header: jarmHeader } = decodeJwtHeader({
1878
+ const { header: jarmHeader } = decodeJwtHeader2({
1698
1879
  jwt: jarmAuthorizationResponseJwt,
1699
1880
  headerSchema: zJarmHeader
1700
1881
  });
@@ -1732,9 +1913,7 @@ async function parseOpenid4vpAuthorizationResponse(options) {
1732
1913
  jarmResponseJwt: authorizationResponse.response,
1733
1914
  callbacks,
1734
1915
  authorizationRequestPayload,
1735
- // If client_id_scheme was provided we should use the legacy (unprefixed) client id scheme
1736
- // TODO: allow both versions, in case of e.g. did:
1737
- expectedClientId: expectedClientId.legacyClientId ?? expectedClientId.clientId
1916
+ expectedClientId: expectedClientId.effectiveClientId
1738
1917
  });
1739
1918
  }
1740
1919
  const authorizationResponsePayload = parseOpenid4VpAuthorizationResponsePayload(authorizationResponse);
@@ -1782,11 +1961,11 @@ var Openid4vpClient = class {
1782
1961
 
1783
1962
  // src/transaction-data/verify-transaction-data.ts
1784
1963
  import {
1785
- HashAlgorithm,
1964
+ HashAlgorithm as HashAlgorithm2,
1786
1965
  Oauth2ErrorCodes as Oauth2ErrorCodes11,
1787
1966
  Oauth2ServerErrorResponseError as Oauth2ServerErrorResponseError13
1788
1967
  } from "@openid4vc/oauth2";
1789
- import { decodeUtf8String, encodeToBase64Url as encodeToBase64Url2 } from "@openid4vc/utils";
1968
+ import { decodeUtf8String, encodeToBase64Url as encodeToBase64Url3 } from "@openid4vc/utils";
1790
1969
  async function verifyTransactionData(options) {
1791
1970
  const parsedTransactionData = parseTransactionData({
1792
1971
  transactionData: options.transactionData
@@ -1809,11 +1988,11 @@ async function verifyTransactionDataEntry({
1809
1988
  }) {
1810
1989
  const allowedAlgs = entry.transactionData.transaction_data_hashes_alg ?? ["sha-256"];
1811
1990
  const supportedAlgs = allowedAlgs.filter(
1812
- (alg) => Object.values(HashAlgorithm).includes(alg)
1991
+ (alg) => Object.values(HashAlgorithm2).includes(alg)
1813
1992
  );
1814
1993
  const hashes = {};
1815
1994
  for (const alg of supportedAlgs) {
1816
- hashes[alg] = encodeToBase64Url2(await callbacks.hash(decodeUtf8String(entry.encoded), alg));
1995
+ hashes[alg] = encodeToBase64Url3(await callbacks.hash(decodeUtf8String(entry.encoded), alg));
1817
1996
  }
1818
1997
  for (const credentialId of entry.transactionData.credential_ids) {
1819
1998
  const transactionDataHashesCredential = credentials[credentialId];
@@ -1829,7 +2008,7 @@ async function verifyTransactionDataEntry({
1829
2008
  if (!hash) {
1830
2009
  throw new Oauth2ServerErrorResponseError13({
1831
2010
  error: Oauth2ErrorCodes11.InvalidTransactionData,
1832
- error_description: `Transaction data entry with index ${entry.transactionDataIndex} is hashed using unsupported alg '${alg}'. This library only supports verification of transaction data hashes using alg values ${Object.values(HashAlgorithm).join(", ")}. Either verify the hashes outside of this library, or limit the allowed alg values to the ones supported by this library.`
2011
+ error_description: `Transaction data entry with index ${entry.transactionDataIndex} is hashed using unsupported alg '${alg}'. This library only supports verification of transaction data hashes using alg values ${Object.values(HashAlgorithm2).join(", ")}. Either verify the hashes outside of this library, or limit the allowed alg values to the ones supported by this library.`
1833
2012
  });
1834
2013
  }
1835
2014
  const credentialHashIndex = transactionDataHashesCredential.transaction_data_hashes.indexOf(hash);
@@ -1885,7 +2064,7 @@ var Openid4vpVerifier = class {
1885
2064
 
1886
2065
  // src/models/z-credential-formats.ts
1887
2066
  import { z as z21 } from "zod";
1888
- var zCredentialFormat = z21.enum(["jwt_vc_json", "ldp_vc", "ac_vc", "mso_mdoc", "dc+sd-jwt", "vc+sd-jwt"]);
2067
+ var zCredentialFormat = z21.enum(["jwt_vc_json", "ldp_vc", "mso_mdoc", "dc+sd-jwt", "vc+sd-jwt"]);
1889
2068
 
1890
2069
  // src/models/z-proof-formats.ts
1891
2070
  import { z as z22 } from "zod";
@@ -1895,8 +2074,13 @@ var zProofFormat = z22.enum(["jwt_vp_json", "ldc_vp", "ac_vp", "dc+sd-jwt", "vc+
1895
2074
  import { z as z23 } from "zod";
1896
2075
  var zWalletMetadata = z23.object({
1897
2076
  presentation_definition_uri_supported: z23.optional(z23.boolean()),
1898
- vp_formats_supported: zVpFormatsSupported,
1899
- client_id_schemes_supported: z23.optional(z23.array(zClientIdScheme)),
2077
+ // Up until draft 26 the legacy format was used
2078
+ vp_formats_supported: z23.optional(zVpFormatsSupported.or(zLegacyVpFormats)),
2079
+ client_id_schemes_supported: z23.optional(
2080
+ // client_id_schemes_supported was from before decentralized_identifier and openid_federation were defined
2081
+ z23.array(zClientIdPrefix.exclude(["decentralized_identifier", "openid_federation"]))
2082
+ ),
2083
+ client_id_prefixes_supported: z23.optional(z23.array(zUniformClientIdPrefix)),
1900
2084
  request_object_signing_alg_values_supported: z23.optional(z23.array(z23.string())),
1901
2085
  authorization_encryption_alg_values_supported: z23.optional(z23.array(z23.string())),
1902
2086
  authorization_encryption_enc_values_supported: z23.optional(z23.array(z23.string()))
@@ -1922,7 +2106,7 @@ export {
1922
2106
  validateOpenid4vpAuthorizationRequestPayload,
1923
2107
  validateOpenid4vpAuthorizationResponsePayload,
1924
2108
  verifyJarmAuthorizationResponse,
1925
- zClientIdScheme,
2109
+ zClientIdPrefix,
1926
2110
  zClientMetadata,
1927
2111
  zCredentialFormat,
1928
2112
  zJarmClientMetadata,