@openid4vc/openid4vci 0.3.0-alpha-20251021081452 → 0.3.0-alpha-20251021082313

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
@@ -733,20 +733,76 @@ const zCredentialIssuerMetadataWithDraftVersion = z.union([zCredentialIssuerMeta
733
733
  originalDraftVersion: Openid4vciDraftVersion.Draft11
734
734
  }))]);
735
735
 
736
+ //#endregion
737
+ //#region src/metadata/credential-issuer/z-signed-credential-issuer-metadata.ts
738
+ const zSignedCredentialIssuerMetadataHeader = z.object({
739
+ ...zJwtHeader.shape,
740
+ typ: z.literal("openidvci-issuer-metadata+jwt")
741
+ }).loose();
742
+ const zSignedCredentialIssuerMetadataPayload = z.object({
743
+ ...zJwtPayload.shape,
744
+ iat: zInteger,
745
+ sub: z.string(),
746
+ ...zCredentialIssuerMetadataDraft14Draft15V1.shape
747
+ }).loose();
748
+
736
749
  //#endregion
737
750
  //#region src/metadata/credential-issuer/credential-issuer-metadata.ts
738
751
  const wellKnownCredentialIssuerSuffix = ".well-known/openid-credential-issuer";
739
752
  /**
740
753
  * @inheritdoc {@link fetchWellKnownMetadata}
741
754
  */
742
- async function fetchCredentialIssuerMetadata(credentialIssuer, fetch) {
755
+ async function fetchCredentialIssuerMetadata(credentialIssuer, options) {
743
756
  const parsedIssuerUrl = new URL(credentialIssuer);
744
757
  const legacyWellKnownMetadataUrl = joinUriParts(credentialIssuer, [wellKnownCredentialIssuerSuffix]);
745
758
  const wellKnownMetadataUrl = joinUriParts(parsedIssuerUrl.origin, [wellKnownCredentialIssuerSuffix, parsedIssuerUrl.pathname]);
746
- let result = await fetchWellKnownMetadata(wellKnownMetadataUrl, zCredentialIssuerMetadataWithDraftVersion, fetch);
747
- if (!result && legacyWellKnownMetadataUrl !== wellKnownMetadataUrl) result = await fetchWellKnownMetadata(legacyWellKnownMetadataUrl, zCredentialIssuerMetadataWithDraftVersion, fetch);
748
- if (result && result.credentialIssuerMetadata.credential_issuer !== credentialIssuer) throw new Oauth2Error(`The 'credential_issuer' parameter '${result.credentialIssuerMetadata.credential_issuer}' in the well known credential issuer metadata at '${wellKnownMetadataUrl}' does not match the provided credential issuer '${credentialIssuer}'.`);
749
- return result;
759
+ const acceptedContentType = options?.callbacks?.verifyJwt ? [ContentType.Jwt, ContentType.Json] : [ContentType.Json];
760
+ const responseSchema = zCredentialIssuerMetadataWithDraftVersion.or(zCompactJwt);
761
+ let result = await fetchWellKnownMetadata(wellKnownMetadataUrl, responseSchema, {
762
+ fetch: options?.callbacks?.fetch,
763
+ acceptedContentType
764
+ });
765
+ if (!result && legacyWellKnownMetadataUrl !== wellKnownMetadataUrl) result = await fetchWellKnownMetadata(legacyWellKnownMetadataUrl, responseSchema, {
766
+ fetch: options?.callbacks?.fetch,
767
+ acceptedContentType
768
+ });
769
+ let issuerMetadataWithVersion = null;
770
+ if (typeof result === "string") {
771
+ if (!options?.callbacks?.verifyJwt) throw new Oauth2Error(`Unable to verify signed credential issuer metadata, no 'verifyJwt' callback provided to fetch credential issuer metadata method.`);
772
+ const { header, payload, signature } = decodeJwt({
773
+ jwt: result,
774
+ headerSchema: zSignedCredentialIssuerMetadataHeader,
775
+ payloadSchema: zSignedCredentialIssuerMetadataPayload
776
+ });
777
+ if (payload.sub !== credentialIssuer) throw new Oauth2Error(`The 'sub' parameter '${payload.sub}' in the signed well known credential issuer metadata at '${wellKnownMetadataUrl}' does not match the provided credential issuer '${credentialIssuer}'.`);
778
+ const signer = jwtSignerFromJwt({
779
+ header,
780
+ payload
781
+ });
782
+ const verifyResult = await verifyJwt({
783
+ compact: result,
784
+ header,
785
+ payload,
786
+ verifyJwtCallback: options.callbacks.verifyJwt,
787
+ now: options.now,
788
+ signer,
789
+ errorMessage: "signed credential issuer metadata jwt verification failed"
790
+ });
791
+ issuerMetadataWithVersion = {
792
+ ...parseWithErrorHandling(zCredentialIssuerMetadataWithDraftVersion, payload, "Unable to determine version for signed issuer metadata"),
793
+ signed: {
794
+ signer: verifyResult.signer,
795
+ jwt: {
796
+ header,
797
+ payload,
798
+ signature,
799
+ compact: result
800
+ }
801
+ }
802
+ };
803
+ } else if (result) issuerMetadataWithVersion = result;
804
+ if (issuerMetadataWithVersion && issuerMetadataWithVersion.credentialIssuerMetadata.credential_issuer !== credentialIssuer) throw new Oauth2Error(`The 'credential_issuer' parameter '${issuerMetadataWithVersion.credentialIssuerMetadata.credential_issuer}' in the well known credential issuer metadata at '${wellKnownMetadataUrl}' does not match the provided credential issuer '${credentialIssuer}'.`);
805
+ return issuerMetadataWithVersion;
750
806
  }
751
807
  /**
752
808
  * Extract credential configuration supported entries where the `format` is known to this
@@ -1371,14 +1427,17 @@ async function verifyCredentialRequestJwtProof(options) {
1371
1427
  //#region src/metadata/fetch-issuer-metadata.ts
1372
1428
  async function resolveIssuerMetadata(credentialIssuer, options) {
1373
1429
  const allowAuthorizationMetadataFromCredentialIssuerMetadata = options?.allowAuthorizationMetadataFromCredentialIssuerMetadata ?? true;
1374
- const credentialIssuerMetadataWithDraftVersion = await fetchCredentialIssuerMetadata(credentialIssuer, options?.fetch);
1430
+ const credentialIssuerMetadataWithDraftVersion = await fetchCredentialIssuerMetadata(credentialIssuer, {
1431
+ callbacks: options?.callbacks,
1432
+ now: options?.now
1433
+ });
1375
1434
  if (!credentialIssuerMetadataWithDraftVersion) throw new Oauth2Error(`Well known credential issuer metadata for issuer '${credentialIssuer}' not found.`);
1376
- const { credentialIssuerMetadata, originalDraftVersion } = credentialIssuerMetadataWithDraftVersion;
1435
+ const { credentialIssuerMetadata, originalDraftVersion, signed } = credentialIssuerMetadataWithDraftVersion;
1377
1436
  const authorizationServers = credentialIssuerMetadata.authorization_servers ?? [credentialIssuer];
1378
1437
  const authoriationServersMetadata = [];
1379
1438
  for (const authorizationServer of authorizationServers) {
1380
1439
  if (options?.restrictToAuthorizationServers && !options.restrictToAuthorizationServers.includes(authorizationServer)) continue;
1381
- let authorizationServerMetadata = await fetchAuthorizationServerMetadata(authorizationServer, options?.fetch);
1440
+ let authorizationServerMetadata = await fetchAuthorizationServerMetadata(authorizationServer, options?.callbacks.fetch);
1382
1441
  if (!authorizationServerMetadata && authorizationServer === credentialIssuer && allowAuthorizationMetadataFromCredentialIssuerMetadata) authorizationServerMetadata = parseWithErrorHandling(zAuthorizationServerMetadata, {
1383
1442
  token_endpoint: credentialIssuerMetadata.token_endpoint,
1384
1443
  issuer: credentialIssuer
@@ -1389,6 +1448,7 @@ async function resolveIssuerMetadata(credentialIssuer, options) {
1389
1448
  return {
1390
1449
  originalDraftVersion,
1391
1450
  credentialIssuer: credentialIssuerMetadata,
1451
+ signedCredentialIssuer: signed,
1392
1452
  authorizationServers: authoriationServersMetadata
1393
1453
  };
1394
1454
  }
@@ -1494,7 +1554,7 @@ var Openid4vciClient = class {
1494
1554
  return resolveCredentialOffer(credentialOffer, { fetch: this.options.callbacks.fetch });
1495
1555
  }
1496
1556
  async resolveIssuerMetadata(credentialIssuer) {
1497
- return resolveIssuerMetadata(credentialIssuer, { fetch: this.options.callbacks.fetch });
1557
+ return resolveIssuerMetadata(credentialIssuer, { callbacks: this.options.callbacks });
1498
1558
  }
1499
1559
  /**
1500
1560
  * Retrieve an authorization code for a presentation during issuance session
@@ -1829,6 +1889,28 @@ async function verifyCredentialRequestAttestationProof(options) {
1829
1889
  });
1830
1890
  }
1831
1891
 
1892
+ //#endregion
1893
+ //#region src/metadata/credential-issuer/signed-credential-issuer-metadata.ts
1894
+ async function createSignedCredentialIssuerMetadataJwt(options) {
1895
+ const header = parseWithErrorHandling(zSignedCredentialIssuerMetadataHeader, {
1896
+ ...jwtHeaderFromJwtSigner(options.signer),
1897
+ typ: "openidvci-issuer-metadata+jwt"
1898
+ });
1899
+ const payload = parseWithErrorHandling(zSignedCredentialIssuerMetadataPayload, {
1900
+ ...options.credentialIssuerMetadata,
1901
+ sub: options.credentialIssuerMetadata.credential_issuer,
1902
+ iat: dateToSeconds(options.issuedAt),
1903
+ exp: options.expiresAt ? dateToSeconds(options.expiresAt) : void 0,
1904
+ iss: options.issuer,
1905
+ ...options.additionalPayload
1906
+ });
1907
+ const { jwt } = await options.callbacks.signJwt(options.signer, {
1908
+ header,
1909
+ payload
1910
+ });
1911
+ return jwt;
1912
+ }
1913
+
1832
1914
  //#endregion
1833
1915
  //#region src/Openid4vciIssuer.ts
1834
1916
  var Openid4vciIssuer = class {
@@ -1847,6 +1929,15 @@ var Openid4vciIssuer = class {
1847
1929
  createCredentialIssuerMetadata(credentialIssuerMetadata) {
1848
1930
  return parseWithErrorHandling(zCredentialIssuerMetadata, credentialIssuerMetadata, "Error validating credential issuer metadata");
1849
1931
  }
1932
+ /**
1933
+ * Validates credential issuer metadata structure is correct and creates signed credential issuer metadata JWT
1934
+ */
1935
+ createSignedCredentialIssuerMetadataJwt(options) {
1936
+ return createSignedCredentialIssuerMetadataJwt({
1937
+ callbacks: this.options.callbacks,
1938
+ ...options
1939
+ });
1940
+ }
1850
1941
  async createCredentialOffer(options) {
1851
1942
  return createCredentialOffer({
1852
1943
  callbacks: this.options.callbacks,