@openid4vc/oauth2 0.3.0-alpha-20250322171044 → 0.3.0-alpha-20250324183425

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
@@ -237,7 +237,9 @@ var zJwtPayload = z5.object({
237
237
  jti: z5.string().optional(),
238
238
  cnf: zJwtConfirmationPayload.optional(),
239
239
  // Reserved for status parameters
240
- status: z5.record(z5.string(), z5.any()).optional()
240
+ status: z5.record(z5.string(), z5.any()).optional(),
241
+ // Reserved for OpenID Federation
242
+ trust_chain: z5.array(z5.string()).nonempty().optional()
241
243
  }).passthrough();
242
244
  var zJwtHeader = z5.object({
243
245
  alg: zAlgValueNotNone,
@@ -245,7 +247,8 @@ var zJwtHeader = z5.object({
245
247
  kid: z5.string().optional(),
246
248
  jwk: zJwk.optional(),
247
249
  x5c: z5.array(z5.string()).optional(),
248
- trust_chain: z5.array(z5.string()).optional()
250
+ // Reserved for OpenID Federation
251
+ trust_chain: z5.array(z5.string()).nonempty().optional()
249
252
  }).passthrough();
250
253
 
251
254
  // src/common/jwt/decode-jwt-header.ts
@@ -299,7 +302,7 @@ function jwtHeaderFromJwtSigner(signer) {
299
302
  kid: signer.didUrl
300
303
  };
301
304
  }
302
- if (signer.method === "trustChain") {
305
+ if (signer.method === "federation") {
303
306
  return {
304
307
  alg: signer.alg,
305
308
  kid: signer.kid,
@@ -323,56 +326,101 @@ function jwtHeaderFromJwtSigner(signer) {
323
326
  alg: signer.alg
324
327
  };
325
328
  }
326
- function jwtSignerFromJwt({ header, payload }) {
329
+ function jwtSignerFromJwt({
330
+ header,
331
+ payload,
332
+ allowedSignerMethods
333
+ }) {
334
+ const found = [];
327
335
  if (header.x5c) {
328
- return {
329
- alg: header.alg,
336
+ found.push({
330
337
  method: "x5c",
331
- x5c: header.x5c
332
- };
338
+ valid: true,
339
+ signer: {
340
+ alg: header.alg,
341
+ method: "x5c",
342
+ x5c: header.x5c
343
+ }
344
+ });
333
345
  }
334
346
  if (header.trust_chain) {
335
347
  if (!header.kid) {
336
- throw new Error(`When 'trust_chain' is used in jwt header, the 'kid' parameter is required.`);
348
+ found.push({
349
+ method: "federation",
350
+ valid: false,
351
+ error: `When 'trust_chain' is used in jwt header, the 'kid' parameter is required.`
352
+ });
353
+ } else {
354
+ found.push({
355
+ method: "federation",
356
+ valid: true,
357
+ signer: {
358
+ alg: header.alg,
359
+ trustChain: header.trust_chain,
360
+ kid: header.kid,
361
+ method: "federation"
362
+ }
363
+ });
337
364
  }
338
- return {
339
- method: "trustChain",
340
- alg: header.alg,
341
- trustChain: header.trust_chain,
342
- kid: header.kid
343
- };
344
365
  }
345
- if (header.kid) {
346
- if (header.kid.startsWith("did:")) {
347
- if (payload.iss && header.kid.startsWith(payload.iss)) {
348
- }
349
- if (!header.kid.includes("#")) {
350
- }
351
- return {
366
+ if (header.kid?.startsWith("did:") || payload.iss?.startsWith("did:")) {
367
+ if (payload.iss && header.kid?.startsWith("did:") && !header.kid.startsWith(payload.iss)) {
368
+ found.push({
352
369
  method: "did",
353
- didUrl: header.kid,
354
- alg: header.alg
355
- };
356
- }
357
- if (header.kid.startsWith("#") && payload.iss?.startsWith("did:")) {
358
- return {
370
+ valid: false,
371
+ error: `kid in header starst with did that is different from did value in 'iss'`
372
+ });
373
+ } else if (!header.kid?.startsWith("did:") && !header.kid?.startsWith("#")) {
374
+ found.push({
359
375
  method: "did",
360
- didUrl: `${payload.iss}${header.kid}`,
361
- alg: header.alg
362
- };
376
+ valid: false,
377
+ error: `kid in header must start with either 'did:' or '#' when 'iss' value is a did`
378
+ });
379
+ } else {
380
+ found.push({
381
+ method: "did",
382
+ valid: true,
383
+ signer: {
384
+ method: "did",
385
+ alg: header.alg,
386
+ didUrl: header.kid.startsWith("did:") ? header.kid : `${payload.iss}${header.kid}`
387
+ }
388
+ });
363
389
  }
364
390
  }
365
391
  if (header.jwk) {
366
- return {
367
- alg: header.alg,
392
+ found.push({
368
393
  method: "jwk",
369
- publicJwk: header.jwk
394
+ signer: { alg: header.alg, method: "jwk", publicJwk: header.jwk },
395
+ valid: true
396
+ });
397
+ }
398
+ const allowedFoundMethods = found.filter((f) => !allowedSignerMethods || allowedSignerMethods?.includes(f.method));
399
+ const allowedValidMethods = allowedFoundMethods.filter((f) => f.valid);
400
+ if (allowedValidMethods.length > 0) {
401
+ return allowedValidMethods[0].signer;
402
+ }
403
+ if (allowedFoundMethods.length > 0) {
404
+ throw new Oauth2Error(
405
+ `Unable to extract signer method from jwt. Found ${allowedFoundMethods.length} allowed signer method(s) but contained invalid configuration:
406
+ ${allowedFoundMethods.map((m) => m.valid ? "" : `FAILED: method ${m.method} - ${m.error}`).join("\n")}`
407
+ );
408
+ }
409
+ if (found.length > 0) {
410
+ throw new Oauth2Error(
411
+ `Unable to extract signer method from jwt. Found ${found.length} signer method(s) that are not allowed:
412
+ ${found.map((m) => m.valid ? `SUCCEEDED: method ${m.method}` : `FAILED: method ${m.method} - ${m.error}`).join("\n")}`
413
+ );
414
+ }
415
+ if (!allowedSignerMethods || allowedSignerMethods.includes("custom")) {
416
+ return {
417
+ method: "custom",
418
+ alg: header.alg
370
419
  };
371
420
  }
372
- return {
373
- method: "custom",
374
- alg: header.alg
375
- };
421
+ throw new Oauth2Error(
422
+ `Unable to extract signer method from jwt. Found no signer methods and 'custom' signer method is not allowed.`
423
+ );
376
424
  }
377
425
 
378
426
  // src/common/jwt/z-jwe.ts