@openeudi/openid4vp 0.6.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -124,6 +124,96 @@ Mismatches return `valid: false` — they do not throw. Only crypto/structural f
124
124
 
125
125
  > **Privacy — diagnostics are verifier-internal.** `match.unmatched[].reason` and `detail` (including `value_mismatch`) are intended for verifier-side logging, debugging, and admin UIs. OpenID4VP §11 warns that per-claim verification outcomes can reveal wallet contents to observers. Do NOT echo these diagnostics into the OpenID4VP wire response sent back to the wallet, into end-user-visible error messages that another party could correlate, or into public analytics/third-party logs. The protocol's own error codes are the public interface; these fields are your internal instrumentation.
126
126
 
127
+ ## Signed authorization requests (x509_san_dns)
128
+
129
+ For flows that require a signed request object (JAR) per OpenID4VP 1.0 §5.10, use `createSignedAuthorizationRequest`:
130
+
131
+ ```ts
132
+ import { createSignedAuthorizationRequest } from "@openeudi/openid4vp";
133
+
134
+ const req = await createSignedAuthorizationRequest({
135
+ hostname: "verifier.example.com",
136
+ requestUri: "https://verifier.example.com/request.jwt",
137
+ responseUri: "https://verifier.example.com/response",
138
+ nonce,
139
+ signer: verifierKeyPair, // CryptoKeyPair with public+private
140
+ certificateChain: [leafCertDer], // DER-encoded, leaf SAN DNSName must equal hostname
141
+ encryptionKey: {
142
+ publicJwk: encryptionPublicJwk, // must include alg, e.g. "ECDH-ES"
143
+ },
144
+ vpFormatsSupported: {
145
+ "dc+sd-jwt": { "sd-jwt_alg_values": ["ES256"] },
146
+ },
147
+ }, dcqlQuery);
148
+
149
+ // req.uri — the short URI to hand to the wallet
150
+ // req.requestObject — the JWS the verifier must host at requestUri
151
+ // (Content-Type: application/oauth-authz-req+jwt)
152
+ ```
153
+
154
+ The caller hosts `req.requestObject` at `requestUri` (the library does not host HTTP). The library verifies that the signing key's public SPKI matches the leaf certificate's public key — an attempt to sign with a mismatched key fails with `SignedRequestBuildError: signing_key_cert_mismatch`.
155
+
156
+ ## Authorization responses (direct_post and direct_post.jwt)
157
+
158
+ Wallets POST the Authorization Response to your `responseUri`. The library is stateless — you MUST compare the envelope's `state` against the value you issued before treating the response as trustworthy. The recommended pattern differs slightly between the unencrypted and encrypted modes.
159
+
160
+ ### Unencrypted (`direct_post`)
161
+
162
+ The envelope arrives as form-encoded JSON; parse it, check `state`, then verify:
163
+
164
+ ```ts
165
+ import { verifyAuthorizationResponse } from "@openeudi/openid4vp";
166
+
167
+ const envelope = parsedVpTokenObject; // { vp_token, state, ... }
168
+
169
+ if (envelope.state !== submittedState) {
170
+ throw new Error("state mismatch — possible CSRF / replay");
171
+ }
172
+
173
+ const result = await verifyAuthorizationResponse(envelope, dcqlQuery, {
174
+ trustedCertificates: [issuerCertDer],
175
+ nonce,
176
+ });
177
+ ```
178
+
179
+ ### Encrypted (`direct_post.jwt`)
180
+
181
+ The wallet wraps the envelope in a JWE. Decrypt explicitly so you can check `state` against the decrypted envelope **before** verification runs:
182
+
183
+ ```ts
184
+ import {
185
+ decryptAuthorizationResponse,
186
+ verifyAuthorizationResponse,
187
+ } from "@openeudi/openid4vp";
188
+
189
+ const decrypted = await decryptAuthorizationResponse(
190
+ form.get("response"), // the JWE string
191
+ verifierEncryptionPrivateKey,
192
+ );
193
+
194
+ if (decrypted.state !== submittedState) {
195
+ throw new Error("state mismatch — possible CSRF / replay");
196
+ }
197
+
198
+ const result = await verifyAuthorizationResponse(decrypted, dcqlQuery, {
199
+ trustedCertificates: [issuerCertDer],
200
+ nonce,
201
+ });
202
+ ```
203
+
204
+ `verifyAuthorizationResponse` also accepts the JWE directly via `{ response: jwe }` together with `options.decryptionKey` — but that path makes the `state` check easy to skip, since the caller never holds the decrypted envelope. Prefer the explicit two-step pattern above.
205
+
206
+ `verifyAuthorizationResponse` accepts the OpenID4VP 1.0 §8.1 envelope shape: `vp_token` is always an object keyed by DCQL credential query id, with arrays of presentations. This release supports **single-credential single-presentation only** — multi-credential queries or multi-presentation arrays throw `MultipleCredentialsNotSupportedError`.
207
+
208
+ ### Supported JWE algorithms
209
+
210
+ `direct_post.jwt` decryption supports:
211
+
212
+ - `alg`: `ECDH-ES` (driven by the encryption JWK's `alg` parameter)
213
+ - `enc`: `A128GCM`, `A256GCM` (HAIP requires both)
214
+
215
+ Other algorithms throw `UnsupportedJweError`.
216
+
127
217
  ### ParseOptions / VerifyOptions
128
218
 
129
219
  Both `parsePresentation` and `verifyPresentation` accept:
package/dist/index.cjs CHANGED
@@ -2,8 +2,8 @@
2
2
 
3
3
  var x509 = require('@peculiar/x509');
4
4
  var uuid = require('uuid');
5
- var cborX = require('cbor-x');
6
5
  var jose = require('jose');
6
+ var cborX = require('cbor-x');
7
7
  var decode = require('@sd-jwt/decode');
8
8
  var dcql = require('@openeudi/dcql');
9
9
  var xmldom = require('@xmldom/xmldom');
@@ -40,7 +40,7 @@ var __export = (target, all) => {
40
40
  };
41
41
 
42
42
  // src/errors.ts
43
- exports.InvalidSignatureError = void 0; exports.ExpiredCredentialError = void 0; exports.UnsupportedFormatError = void 0; exports.MalformedCredentialError = void 0; exports.NonceValidationError = void 0; exports.HaipValidationError = void 0; exports.OpenID4VPError = void 0; exports.TrustAnchorNotFoundError = void 0; exports.CertificateChainError = void 0; exports.RevokedCertificateError = void 0; exports.RevocationCheckFailedError = void 0; exports.LotlFetchError = void 0; exports.LotlSignatureError = void 0;
43
+ exports.InvalidSignatureError = void 0; exports.ExpiredCredentialError = void 0; exports.UnsupportedFormatError = void 0; exports.MalformedCredentialError = void 0; exports.NonceValidationError = void 0; exports.HaipValidationError = void 0; exports.OpenID4VPError = void 0; exports.TrustAnchorNotFoundError = void 0; exports.CertificateChainError = void 0; exports.RevokedCertificateError = void 0; exports.RevocationCheckFailedError = void 0; exports.LotlFetchError = void 0; exports.LotlSignatureError = void 0; exports.SignedRequestBuildError = void 0; exports.UnsupportedJweError = void 0; exports.DecryptionFailedError = void 0; exports.MissingDecryptionKeyError = void 0; exports.MultipleCredentialsNotSupportedError = void 0;
44
44
  var init_errors = __esm({
45
45
  "src/errors.ts"() {
46
46
  exports.InvalidSignatureError = class extends Error {
@@ -136,6 +136,47 @@ var init_errors = __esm({
136
136
  exports.LotlSignatureError = class extends exports.OpenID4VPError {
137
137
  code = "lotl_signature_invalid";
138
138
  };
139
+ exports.SignedRequestBuildError = class extends exports.OpenID4VPError {
140
+ code;
141
+ constructor(code, message) {
142
+ super(message);
143
+ this.code = code;
144
+ }
145
+ };
146
+ exports.UnsupportedJweError = class extends exports.OpenID4VPError {
147
+ code = "unsupported_jwe";
148
+ alg;
149
+ enc;
150
+ constructor(alg, enc) {
151
+ super(`Unsupported JWE algorithms: alg=${alg}, enc=${enc}`);
152
+ this.alg = alg;
153
+ this.enc = enc;
154
+ }
155
+ };
156
+ exports.DecryptionFailedError = class extends exports.OpenID4VPError {
157
+ code = "decryption_failed";
158
+ constructor(message = "Failed to decrypt authorization response", options) {
159
+ super(message, options);
160
+ }
161
+ };
162
+ exports.MissingDecryptionKeyError = class extends exports.OpenID4VPError {
163
+ code = "missing_decryption_key";
164
+ constructor(message = "decryptionKey is required to verify a direct_post.jwt response") {
165
+ super(message);
166
+ }
167
+ };
168
+ exports.MultipleCredentialsNotSupportedError = class extends exports.OpenID4VPError {
169
+ code = "multi_credential_unsupported";
170
+ entryCount;
171
+ presentationCount;
172
+ constructor(entryCount, presentationCount) {
173
+ super(
174
+ `Multi-credential presentations are not yet supported: ${entryCount} queryId entries, ${presentationCount} presentations`
175
+ );
176
+ this.entryCount = entryCount;
177
+ this.presentationCount = presentationCount;
178
+ }
179
+ };
139
180
  }
140
181
  });
141
182
 
@@ -8045,6 +8086,135 @@ function createAuthorizationRequest(input, query) {
8045
8086
  };
8046
8087
  }
8047
8088
 
8089
+ // src/signed-authorization.ts
8090
+ init_errors();
8091
+ var DEFAULT_SUPPORTED_ENC_VALUES = ["A128GCM", "A256GCM"];
8092
+ var SUPPORTED_SIGNING_ALGS = /* @__PURE__ */ new Set(["ES256", "ES384", "RS256"]);
8093
+ async function createSignedAuthorizationRequest(input, query) {
8094
+ if (input.certificateChain.length === 0) {
8095
+ throw new exports.SignedRequestBuildError(
8096
+ "empty_cert_chain",
8097
+ "certificateChain must contain at least the leaf certificate"
8098
+ );
8099
+ }
8100
+ const signingAlg = input.signingAlgorithm ?? "ES256";
8101
+ if (!SUPPORTED_SIGNING_ALGS.has(signingAlg)) {
8102
+ throw new exports.SignedRequestBuildError(
8103
+ "unsupported_signing_alg",
8104
+ `signingAlgorithm ${signingAlg} is not supported (expected ES256/ES384/RS256)`
8105
+ );
8106
+ }
8107
+ if (!input.vpFormatsSupported || Object.keys(input.vpFormatsSupported).length === 0) {
8108
+ throw new exports.SignedRequestBuildError(
8109
+ "missing_vp_formats",
8110
+ "vpFormatsSupported is required and must be non-empty"
8111
+ );
8112
+ }
8113
+ const leafCert = new x509.X509Certificate(toArrayBuffer(input.certificateChain[0]));
8114
+ const sanDnsNames = extractDnsNames(leafCert);
8115
+ if (!sanDnsNames.includes(input.hostname)) {
8116
+ throw new exports.SignedRequestBuildError(
8117
+ "hostname_cert_mismatch",
8118
+ `leaf cert SAN DNSName values [${sanDnsNames.join(", ")}] do not include hostname "${input.hostname}"`
8119
+ );
8120
+ }
8121
+ const signerPublicSpki = new Uint8Array(
8122
+ await crypto.subtle.exportKey("spki", input.signer.publicKey)
8123
+ );
8124
+ const leafSpki = new Uint8Array(leafCert.publicKey.rawData);
8125
+ if (!bytesEqual(signerPublicSpki, leafSpki)) {
8126
+ throw new exports.SignedRequestBuildError(
8127
+ "signing_key_cert_mismatch",
8128
+ "signer.publicKey SPKI does not match leaf certificate SPKI"
8129
+ );
8130
+ }
8131
+ const responseMode = input.responseMode ?? "direct_post.jwt";
8132
+ if (responseMode === "direct_post.jwt") {
8133
+ if (!input.encryptionKey?.publicJwk) {
8134
+ throw new exports.SignedRequestBuildError(
8135
+ "missing_encryption_jwk",
8136
+ "direct_post.jwt response mode requires encryptionKey.publicJwk"
8137
+ );
8138
+ }
8139
+ if (!input.encryptionKey.publicJwk.alg) {
8140
+ throw new exports.SignedRequestBuildError(
8141
+ "missing_encryption_alg",
8142
+ "encryptionKey.publicJwk must carry alg (OpenID4VP 1.0 \xA78.3)"
8143
+ );
8144
+ }
8145
+ }
8146
+ const state = input.state ?? uuid.v4();
8147
+ const clientId = `x509_san_dns:${input.hostname}`;
8148
+ const now = Math.floor(Date.now() / 1e3);
8149
+ const clientMetadata = {
8150
+ vp_formats_supported: input.vpFormatsSupported
8151
+ };
8152
+ if (responseMode === "direct_post.jwt" && input.encryptionKey) {
8153
+ const enc = input.encryptionKey.supportedEncValues;
8154
+ if (enc !== void 0 && enc.length === 0) {
8155
+ throw new exports.SignedRequestBuildError(
8156
+ "empty_supported_enc_values",
8157
+ "encryptionKey.supportedEncValues must not be empty (omit to use defaults [A128GCM, A256GCM])"
8158
+ );
8159
+ }
8160
+ const jwk = { ...input.encryptionKey.publicJwk, use: "enc" };
8161
+ clientMetadata.jwks = { keys: [jwk] };
8162
+ clientMetadata.encrypted_response_enc_values_supported = enc ?? [...DEFAULT_SUPPORTED_ENC_VALUES];
8163
+ }
8164
+ const payload = {
8165
+ iss: clientId,
8166
+ aud: "https://self-issued.me/v2",
8167
+ response_type: "vp_token",
8168
+ response_mode: responseMode,
8169
+ client_id: clientId,
8170
+ response_uri: input.responseUri,
8171
+ nonce: input.nonce,
8172
+ state,
8173
+ dcql_query: query,
8174
+ client_metadata: clientMetadata,
8175
+ iat: now,
8176
+ exp: now + 120
8177
+ };
8178
+ const x5c = input.certificateChain.map((der) => bytesToBase64(der));
8179
+ const jws = await new jose.SignJWT(payload).setProtectedHeader({ typ: "oauth-authz-req+jwt", alg: signingAlg, x5c }).sign(input.signer.privateKey);
8180
+ const uriParams = new URLSearchParams({
8181
+ client_id: clientId,
8182
+ request_uri: input.requestUri
8183
+ });
8184
+ return {
8185
+ uri: `openid4vp://authorize?${uriParams.toString()}`,
8186
+ requestObject: jws,
8187
+ dcqlQuery: query,
8188
+ nonce: input.nonce,
8189
+ state
8190
+ };
8191
+ }
8192
+ function extractDnsNames(cert) {
8193
+ const SAN_OID = "2.5.29.17";
8194
+ const ext = cert.extensions.find((e) => e.type === SAN_OID);
8195
+ if (!ext) return [];
8196
+ const names = ext.names;
8197
+ const items = names?.items ?? [];
8198
+ return items.filter((e) => e.type === "dns").map((e) => e.value);
8199
+ }
8200
+ function bytesEqual(a, b) {
8201
+ if (a.length !== b.length) return false;
8202
+ for (let i = 0; i < a.length; i++) {
8203
+ if (a[i] !== b[i]) return false;
8204
+ }
8205
+ return true;
8206
+ }
8207
+ function bytesToBase64(bytes) {
8208
+ let s = "";
8209
+ for (let i = 0; i < bytes.length; i++) s += String.fromCharCode(bytes[i]);
8210
+ return btoa(s);
8211
+ }
8212
+ function toArrayBuffer(bytes) {
8213
+ const out = new ArrayBuffer(bytes.byteLength);
8214
+ new Uint8Array(out).set(bytes);
8215
+ return out;
8216
+ }
8217
+
8048
8218
  // src/haip.ts
8049
8219
  init_errors();
8050
8220
  var HAIP_DOCTYPE_NAMESPACES = {
@@ -8271,7 +8441,7 @@ async function computeItemDigest(itemBytes, digestAlgorithm) {
8271
8441
  const buf = await crypto.subtle.digest(digestAlgorithm, new Uint8Array(itemBytes));
8272
8442
  return new Uint8Array(buf);
8273
8443
  }
8274
- function bytesEqual(a, b) {
8444
+ function bytesEqual2(a, b) {
8275
8445
  if (a.length !== b.length) return false;
8276
8446
  for (let i = 0; i < a.length; i++) {
8277
8447
  if (a[i] !== b[i]) return false;
@@ -8317,7 +8487,7 @@ async function verifyAllDigests(nameSpaces, mso) {
8317
8487
  if (!expectedDigest) {
8318
8488
  throw new exports.MalformedCredentialError(`digestID ${digestID} missing from MSO valueDigests[${ns}]`);
8319
8489
  }
8320
- if (!bytesEqual(hash, expectedDigest)) {
8490
+ if (!bytesEqual2(hash, expectedDigest)) {
8321
8491
  throw new exports.MalformedCredentialError(`digest mismatch for ns=${ns} digestID=${digestID}`);
8322
8492
  }
8323
8493
  }
@@ -8436,7 +8606,7 @@ init_errors();
8436
8606
  var decoder4 = new cborX.Encoder({ mapsAsObjects: false, useRecords: false });
8437
8607
  var encoder = new cborX.Encoder({ mapsAsObjects: false, useRecords: false });
8438
8608
  var DEFAULT_ALLOWED_ALGORITHMS = ["ES256", "ES384", "ES512"];
8439
- function bytesEqual2(a, b) {
8609
+ function bytesEqual3(a, b) {
8440
8610
  if (a.length !== b.length) return false;
8441
8611
  for (let i = 0; i < a.length; i++) {
8442
8612
  if (a[i] !== b[i]) return false;
@@ -8572,8 +8742,8 @@ var MdocParser = class {
8572
8742
  cache: options.cache,
8573
8743
  clockSkewTolerance: options.clockSkewTolerance
8574
8744
  });
8575
- const { X509Certificate: X509Certificate8 } = await import('@peculiar/x509');
8576
- const leaf = new X509Certificate8(issuerCertBytes);
8745
+ const { X509Certificate: X509Certificate9 } = await import('@peculiar/x509');
8746
+ const leaf = new X509Certificate9(issuerCertBytes);
8577
8747
  trustResult = await evaluator.evaluate(leaf);
8578
8748
  } else {
8579
8749
  if (options.trustedCertificates.length === 0) {
@@ -8583,7 +8753,7 @@ var MdocParser = class {
8583
8753
  );
8584
8754
  }
8585
8755
  } else {
8586
- const trusted = options.trustedCertificates.some((t) => bytesEqual2(t, issuerCertBytes));
8756
+ const trusted = options.trustedCertificates.some((t) => bytesEqual3(t, issuerCertBytes));
8587
8757
  if (!trusted) {
8588
8758
  return {
8589
8759
  valid: false,
@@ -8698,7 +8868,7 @@ function base64ToBytes(base64) {
8698
8868
  }
8699
8869
  return bytes;
8700
8870
  }
8701
- function bytesEqual3(a, b) {
8871
+ function bytesEqual4(a, b) {
8702
8872
  if (a.length !== b.length) return false;
8703
8873
  for (let i = 0; i < a.length; i++) {
8704
8874
  if (a[i] !== b[i]) return false;
@@ -8821,8 +8991,8 @@ var SdJwtParser = class {
8821
8991
  cache: options.cache,
8822
8992
  clockSkewTolerance: options.clockSkewTolerance
8823
8993
  });
8824
- const { X509Certificate: X509Certificate8 } = await import('@peculiar/x509');
8825
- const leaf = new X509Certificate8(issuerCertBytes);
8994
+ const { X509Certificate: X509Certificate9 } = await import('@peculiar/x509');
8995
+ const leaf = new X509Certificate9(issuerCertBytes);
8826
8996
  trustResult = await evaluator.evaluate(leaf);
8827
8997
  } else {
8828
8998
  if (options.trustedCertificates.length === 0) {
@@ -8832,7 +9002,7 @@ var SdJwtParser = class {
8832
9002
  );
8833
9003
  }
8834
9004
  } else {
8835
- const isTrusted = options.trustedCertificates.some((trusted) => bytesEqual3(trusted, issuerCertBytes));
9005
+ const isTrusted = options.trustedCertificates.some((trusted) => bytesEqual4(trusted, issuerCertBytes));
8836
9006
  if (!isTrusted) {
8837
9007
  return invalidResult("Issuer certificate is not trusted");
8838
9008
  }
@@ -8929,6 +9099,44 @@ async function parsePresentation(vpToken, options) {
8929
9099
  error: "Unsupported credential format"
8930
9100
  };
8931
9101
  }
9102
+
9103
+ // src/decrypt-response.ts
9104
+ init_errors();
9105
+ var SUPPORTED_ALG = "ECDH-ES";
9106
+ var SUPPORTED_ENC = /* @__PURE__ */ new Set(["A128GCM", "A256GCM"]);
9107
+ async function decryptAuthorizationResponse(jwe, privateKey) {
9108
+ let header;
9109
+ try {
9110
+ header = jose.decodeProtectedHeader(jwe);
9111
+ } catch (err) {
9112
+ throw new exports.DecryptionFailedError("Malformed JWE header", {
9113
+ cause: err
9114
+ });
9115
+ }
9116
+ const alg = typeof header.alg === "string" ? header.alg : "";
9117
+ const enc = typeof header.enc === "string" ? header.enc : "";
9118
+ if (alg !== SUPPORTED_ALG || !SUPPORTED_ENC.has(enc)) {
9119
+ throw new exports.UnsupportedJweError(alg, enc);
9120
+ }
9121
+ let plaintext;
9122
+ try {
9123
+ const result = await jose.compactDecrypt(jwe, privateKey);
9124
+ plaintext = result.plaintext;
9125
+ } catch (err) {
9126
+ throw new exports.DecryptionFailedError(void 0, { cause: err });
9127
+ }
9128
+ try {
9129
+ const text = new TextDecoder().decode(plaintext);
9130
+ return JSON.parse(text);
9131
+ } catch (err) {
9132
+ throw new exports.DecryptionFailedError("Decrypted plaintext is not valid JSON", {
9133
+ cause: err
9134
+ });
9135
+ }
9136
+ }
9137
+
9138
+ // src/verify.ts
9139
+ init_errors();
8932
9140
  var INTERNAL_TO_DCQL_FORMAT = {
8933
9141
  "sd-jwt-vc": "dc+sd-jwt",
8934
9142
  mdoc: "mso_mdoc"
@@ -8960,6 +9168,48 @@ async function verifyPresentation(vpToken, query, options) {
8960
9168
  valid: parsed.valid && match.satisfied
8961
9169
  };
8962
9170
  }
9171
+ function isEncryptedResponse(x) {
9172
+ return typeof x === "object" && x !== null && "response" in x && typeof x.response === "string" && Object.keys(x).length === 1;
9173
+ }
9174
+ function isAuthorizationResponse(x) {
9175
+ return typeof x === "object" && x !== null && "vp_token" in x && typeof x.vp_token === "object" && x.vp_token !== null;
9176
+ }
9177
+ async function verifyAuthorizationResponse(envelope, query, options) {
9178
+ if (isEncryptedResponse(envelope)) {
9179
+ if (!options.decryptionKey) {
9180
+ throw new exports.MissingDecryptionKeyError();
9181
+ }
9182
+ const decrypted = await decryptAuthorizationResponse(
9183
+ envelope.response,
9184
+ options.decryptionKey
9185
+ );
9186
+ return verifyAuthorizationResponse(decrypted, query, options);
9187
+ }
9188
+ if (!isAuthorizationResponse(envelope)) {
9189
+ throw new TypeError("envelope must contain vp_token as a JSON object per OpenID4VP 1.0 \xA78.1");
9190
+ }
9191
+ const vpToken = envelope.vp_token;
9192
+ const queryIds = Object.keys(vpToken);
9193
+ if (queryIds.length === 0) {
9194
+ throw new TypeError("vp_token cannot be empty per OpenID4VP 1.0 \xA78.1");
9195
+ }
9196
+ for (const id of queryIds) {
9197
+ if (!Array.isArray(vpToken[id])) {
9198
+ throw new TypeError(
9199
+ `vp_token entry "${id}" must be an array of presentations per OpenID4VP 1.0 \xA78.1`
9200
+ );
9201
+ }
9202
+ }
9203
+ const presentationCount = queryIds.reduce(
9204
+ (sum, id) => sum + vpToken[id].length,
9205
+ 0
9206
+ );
9207
+ if (queryIds.length > 1 || presentationCount > 1) {
9208
+ throw new exports.MultipleCredentialsNotSupportedError(queryIds.length, presentationCount);
9209
+ }
9210
+ const presentation = vpToken[queryIds[0]][0];
9211
+ return verifyPresentation(presentation, query, options);
9212
+ }
8963
9213
 
8964
9214
  // src/index.ts
8965
9215
  init_errors();
@@ -9571,7 +9821,7 @@ function equalBytes(a, b) {
9571
9821
 
9572
9822
  // src/index.ts
9573
9823
  init_errors();
9574
- var VERSION = "0.5.0";
9824
+ var VERSION = "0.7.0";
9575
9825
  /*! Bundled license information:
9576
9826
 
9577
9827
  pvtsutils/build/index.es.js:
@@ -9659,9 +9909,12 @@ exports.StaticTrustStore = StaticTrustStore;
9659
9909
  exports.VERSION = VERSION;
9660
9910
  exports.buildHaipQuery = buildHaipQuery;
9661
9911
  exports.createAuthorizationRequest = createAuthorizationRequest;
9912
+ exports.createSignedAuthorizationRequest = createSignedAuthorizationRequest;
9913
+ exports.decryptAuthorizationResponse = decryptAuthorizationResponse;
9662
9914
  exports.isHaipQuery = isHaipQuery;
9663
9915
  exports.parsePresentation = parsePresentation;
9664
9916
  exports.validateHaipQuery = validateHaipQuery;
9917
+ exports.verifyAuthorizationResponse = verifyAuthorizationResponse;
9665
9918
  exports.verifyPresentation = verifyPresentation;
9666
9919
  //# sourceMappingURL=index.cjs.map
9667
9920
  //# sourceMappingURL=index.cjs.map