@openid4vc/openid4vp 0.3.0-alpha-20250315153126 → 0.3.0-alpha-20250318163628

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,58 +1,50 @@
1
- // src/client-identifier-scheme/z-client-id-scheme.ts
2
- import { z } from "zod";
3
- var zClientIdScheme = z.enum([
4
- "pre-registered",
5
- "redirect_uri",
6
- "https",
7
- "verifier_attestation",
8
- "did",
9
- "x509_san_dns",
10
- "x509_san_uri",
11
- "web-origin"
12
- ]);
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";
13
4
 
14
- // src/jarm/jarm-authorization-response/verify-jarm-authorization-response.ts
15
- import {
16
- Oauth2Error as Oauth2Error3,
17
- decodeJwt,
18
- jwtSignerFromJwt,
19
- zCompactJwe,
20
- zCompactJwt,
21
- zJwtHeader as zJwtHeader2
22
- } from "@openid4vc/oauth2";
23
- import z4 from "zod";
5
+ // src/authorization-request/z-authorization-request-dc-api.ts
6
+ import { z as z5 } from "zod";
7
+
8
+ // src/authorization-request/z-authorization-request.ts
9
+ import { URL, zHttpsUrl as zHttpsUrl2 } from "@openid4vc/utils";
10
+ import { z as z4 } from "zod";
11
+
12
+ // src/models/z-client-metadata.ts
13
+ import { zJwkSet } from "@openid4vc/oauth2";
14
+ import { zHttpsUrl } from "@openid4vc/utils";
15
+ import { z as z3 } from "zod";
24
16
 
25
17
  // src/jarm/metadata/z-jarm-client-metadata.ts
26
18
  import { Oauth2Error, zAlgValueNotNone } from "@openid4vc/oauth2";
27
19
  import { parseWithErrorHandling } from "@openid4vc/utils";
28
- import { z as z2 } from "zod";
29
- var zJarmSignOnlyClientMetadata = z2.object({
20
+ import { z } from "zod";
21
+ var zJarmSignOnlyClientMetadata = z.object({
30
22
  authorization_signed_response_alg: zAlgValueNotNone,
31
- authorization_encrypted_response_alg: z2.optional(z2.never()),
32
- authorization_encrypted_response_enc: z2.optional(z2.never())
23
+ authorization_encrypted_response_alg: z.optional(z.never()),
24
+ authorization_encrypted_response_enc: z.optional(z.never())
33
25
  });
34
- var zJarmEncryptOnlyClientMetadata = z2.object({
35
- authorization_signed_response_alg: z2.optional(z2.never()),
36
- authorization_encrypted_response_alg: z2.string(),
37
- authorization_encrypted_response_enc: z2.optional(z2.string())
26
+ var zJarmEncryptOnlyClientMetadata = z.object({
27
+ authorization_signed_response_alg: z.optional(z.never()),
28
+ authorization_encrypted_response_alg: z.string(),
29
+ authorization_encrypted_response_enc: z.optional(z.string())
38
30
  });
39
- var zJarmSignEncryptClientMetadata = z2.object({
31
+ var zJarmSignEncryptClientMetadata = z.object({
40
32
  authorization_signed_response_alg: zJarmSignOnlyClientMetadata.shape.authorization_signed_response_alg,
41
33
  authorization_encrypted_response_alg: zJarmEncryptOnlyClientMetadata.shape.authorization_encrypted_response_alg,
42
34
  authorization_encrypted_response_enc: zJarmEncryptOnlyClientMetadata.shape.authorization_encrypted_response_enc
43
35
  });
44
- var zJarmClientMetadata = z2.object({
45
- authorization_signed_response_alg: z2.optional(zJarmSignOnlyClientMetadata.shape.authorization_signed_response_alg),
46
- authorization_encrypted_response_alg: z2.optional(
36
+ var zJarmClientMetadata = z.object({
37
+ authorization_signed_response_alg: z.optional(zJarmSignOnlyClientMetadata.shape.authorization_signed_response_alg),
38
+ authorization_encrypted_response_alg: z.optional(
47
39
  zJarmEncryptOnlyClientMetadata.shape.authorization_encrypted_response_alg
48
40
  ),
49
- authorization_encrypted_response_enc: z2.optional(
41
+ authorization_encrypted_response_enc: z.optional(
50
42
  zJarmEncryptOnlyClientMetadata.shape.authorization_encrypted_response_enc
51
43
  )
52
44
  });
53
45
  var zJarmClientMetadataParsed = zJarmClientMetadata.transform((client_metadata) => {
54
46
  const parsedClientMeta = parseWithErrorHandling(
55
- z2.union([zJarmEncryptOnlyClientMetadata, zJarmSignOnlyClientMetadata, zJarmSignEncryptClientMetadata]),
47
+ z.union([zJarmEncryptOnlyClientMetadata, zJarmSignOnlyClientMetadata, zJarmSignEncryptClientMetadata]),
56
48
  client_metadata,
57
49
  "Invalid jarm client metadata."
58
50
  );
@@ -89,766 +81,799 @@ var zJarmClientMetadataParsed = zJarmClientMetadata.transform((client_metadata)
89
81
  throw new Oauth2Error("Invalid jarm client metadata. Failed to parse.");
90
82
  });
91
83
 
92
- // src/jarm/jarm-extract-jwks.ts
93
- function extractJwksFromClientMetadata(clientMetadata) {
94
- const parsed = zJarmClientMetadataParsed.parse(clientMetadata);
95
- const encryptionAlg = parsed.client_metadata.authorization_encrypted_response_enc;
96
- const signingAlg = parsed.client_metadata.authorization_signed_response_alg;
97
- 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
98
- clientMetadata.jwks.keys?.[0];
99
- 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
100
- clientMetadata.jwks.keys?.[0];
101
- return { encJwk, sigJwk };
102
- }
103
-
104
- // src/jarm/jarm-authorization-response/jarm-validate-authorization-response.ts
105
- import { Oauth2Error as Oauth2Error2 } from "@openid4vc/oauth2";
106
- import { dateToSeconds } from "@openid4vc/utils";
84
+ // src/models/z-vp-formats-supported.ts
85
+ import { z as z2 } from "zod";
86
+ var zVpFormatsSupported = z2.record(
87
+ z2.string(),
88
+ z2.object({
89
+ alg_values_supported: z2.optional(z2.array(z2.string()))
90
+ }).passthrough()
91
+ );
107
92
 
108
- // src/jarm/jarm-authorization-response/z-jarm-authorization-response.ts
109
- import { zJwtHeader, zJwtPayload } from "@openid4vc/oauth2";
110
- import { z as z3 } from "zod";
111
- var zJarmHeader = z3.object({ ...zJwtHeader.shape, apu: z3.string().optional(), apv: z3.string().optional() });
112
- var zJarmAuthorizationResponse = z3.object({
113
- /**
114
- * iss: The issuer URL of the authorization server that created the response
115
- * aud: The client_id of the client the response is intended for
116
- * exp: The expiration time of the JWT. A maximum JWT lifetime of 10 minutes is RECOMMENDED.
117
- */
118
- ...zJwtPayload.shape,
119
- ...zJwtPayload.pick({ iss: true, aud: true, exp: true }).required().shape,
120
- state: z3.optional(z3.string())
121
- }).passthrough();
122
- var zJarmAuthorizationResponseEncryptedOnly = z3.object({
123
- ...zJwtPayload.shape,
124
- state: z3.optional(z3.string())
93
+ // src/models/z-client-metadata.ts
94
+ var zClientMetadata = z3.object({
95
+ jwks: z3.optional(zJwkSet),
96
+ vp_formats: z3.optional(zVpFormatsSupported),
97
+ ...zJarmClientMetadata.shape,
98
+ logo_uri: zHttpsUrl.optional(),
99
+ client_name: z3.string().optional()
125
100
  }).passthrough();
126
101
 
127
- // src/jarm/jarm-authorization-response/jarm-validate-authorization-response.ts
128
- var jarmAuthorizationResponseValidate = (options) => {
129
- const { expectedClientId, authorizationResponse } = options;
130
- if (!zJarmAuthorizationResponse.safeParse(authorizationResponse).success) {
131
- return;
132
- }
133
- if (expectedClientId !== authorizationResponse.aud) {
134
- throw new Oauth2Error2(
135
- `Invalid 'aud' claim in JARM authorization response. Expected '${expectedClientId}' received '${JSON.stringify(authorizationResponse.aud)}'.`
136
- );
137
- }
138
- if (authorizationResponse.exp !== void 0 && authorizationResponse.exp < dateToSeconds()) {
139
- throw new Oauth2Error2("Jarm auth response is expired.");
140
- }
141
- };
142
-
143
- // src/jarm/jarm-authorization-response/verify-jarm-authorization-response.ts
144
- var decryptJarmAuthorizationResponseJwt = async (options) => {
145
- const { jarmAuthorizationResponseJwt, callbacks, authorizationRequestPayload } = options;
146
- const encryptionJwk = authorizationRequestPayload.client_metadata?.jwks ? extractJwksFromClientMetadata({
147
- ...authorizationRequestPayload.client_metadata,
148
- jwks: authorizationRequestPayload.client_metadata.jwks
149
- }).encJwk : void 0;
150
- const result = await callbacks.decryptJwe(jarmAuthorizationResponseJwt, { jwk: encryptionJwk });
151
- if (!result.decrypted) {
152
- throw new Oauth2Error3("Failed to decrypt jarm auth response.");
153
- }
154
- return result.payload;
155
- };
156
- async function verifyJarmAuthorizationResponse(options) {
157
- const { jarmAuthorizationResponseJwt, callbacks, expectedClientId, authorizationRequestPayload } = options;
158
- const requestDataIsEncrypted = zCompactJwe.safeParse(jarmAuthorizationResponseJwt).success;
159
- const decryptedRequestData = requestDataIsEncrypted ? await decryptJarmAuthorizationResponseJwt({
160
- jarmAuthorizationResponseJwt,
161
- callbacks,
162
- authorizationRequestPayload
163
- }) : jarmAuthorizationResponseJwt;
164
- const responseIsSigned = zCompactJwt.safeParse(decryptedRequestData).success;
165
- if (!requestDataIsEncrypted && !responseIsSigned) {
166
- throw new Oauth2Error3("Jarm Auth Response must be either encrypted, signed, or signed and encrypted.");
167
- }
168
- let jarmAuthorizationResponse;
169
- if (responseIsSigned) {
170
- const { header: jwsProtectedHeader, payload: jwsPayload } = decodeJwt({
171
- jwt: decryptedRequestData,
172
- headerSchema: z4.object({ ...zJwtHeader2.shape, kid: z4.string() })
173
- });
174
- const response = zJarmAuthorizationResponse.parse(jwsPayload);
175
- const jwtSigner = jwtSignerFromJwt({ header: jwsProtectedHeader, payload: jwsPayload });
176
- const verificationResult = await options.callbacks.verifyJwt(jwtSigner, {
177
- compact: decryptedRequestData,
178
- header: jwsProtectedHeader,
179
- payload: jwsPayload
102
+ // src/authorization-request/z-authorization-request.ts
103
+ var zStringToJson = z4.string().transform((string, ctx) => {
104
+ try {
105
+ return JSON.parse(string);
106
+ } catch (error) {
107
+ ctx.addIssue({
108
+ code: "custom",
109
+ message: "Expected a JSON string, but could not parse the string to JSON"
180
110
  });
181
- if (!verificationResult.verified) {
182
- throw new Oauth2Error3("Jarm Auth Response is not valid.");
183
- }
184
- jarmAuthorizationResponse = response;
185
- } else {
186
- const jsonRequestData = JSON.parse(decryptedRequestData);
187
- jarmAuthorizationResponse = zJarmAuthorizationResponseEncryptedOnly.parse(jsonRequestData);
111
+ return z4.NEVER;
188
112
  }
189
- jarmAuthorizationResponseValidate({
190
- expectedClientId,
191
- authorizationResponse: jarmAuthorizationResponse
192
- });
193
- const type = requestDataIsEncrypted && responseIsSigned ? "SignedEncrypted" /* SignedEncrypted */ : requestDataIsEncrypted ? "Encrypted" /* Encrypted */ : "Signed" /* Signed */;
194
- const issuer = jarmAuthorizationResponse.iss;
195
- return { jarmAuthorizationResponse, type, issuer };
196
- }
197
-
198
- // src/authorization-request/create-authorization-request.ts
199
- import { Oauth2Error as Oauth2Error4 } from "@openid4vc/oauth2";
200
- import { URL, URLSearchParams, objectToQueryParams, parseWithErrorHandling as parseWithErrorHandling2 } from "@openid4vc/utils";
113
+ });
114
+ var zOpenid4vpAuthorizationRequest = z4.object({
115
+ response_type: z4.literal("vp_token"),
116
+ client_id: z4.string(),
117
+ redirect_uri: zHttpsUrl2.optional(),
118
+ response_uri: zHttpsUrl2.optional(),
119
+ request_uri: zHttpsUrl2.optional(),
120
+ request_uri_method: z4.optional(z4.string()),
121
+ response_mode: z4.enum(["direct_post", "direct_post.jwt"]).optional(),
122
+ nonce: z4.string(),
123
+ wallet_nonce: z4.string().optional(),
124
+ scope: z4.string().optional(),
125
+ presentation_definition: z4.record(z4.any()).or(zStringToJson).optional(),
126
+ presentation_definition_uri: zHttpsUrl2.optional(),
127
+ dcql_query: z4.record(z4.any()).or(zStringToJson).optional(),
128
+ client_metadata: zClientMetadata.optional(),
129
+ client_metadata_uri: zHttpsUrl2.optional(),
130
+ state: z4.string().optional(),
131
+ transaction_data: z4.array(z4.string().base64url()).optional(),
132
+ trust_chain: z4.unknown().optional(),
133
+ client_id_scheme: z4.enum([
134
+ "pre-registered",
135
+ "redirect_uri",
136
+ "entity_id",
137
+ "did",
138
+ "verifier_attestation",
139
+ "x509_san_dns",
140
+ "x509_san_uri"
141
+ ]).optional()
142
+ }).passthrough();
143
+ var zOpenid4vpAuthorizationRequestFromUriParams = z4.string().url().transform((url) => Object.fromEntries(new URL(url).searchParams)).pipe(
144
+ z4.object({
145
+ presentation_definition: zStringToJson.optional(),
146
+ client_metadata: zStringToJson.optional(),
147
+ dcql_query: zStringToJson.optional(),
148
+ transaction_data: zStringToJson.optional()
149
+ }).passthrough()
150
+ );
201
151
 
202
- // src/jar/create-jar-authorization-request.ts
203
- import {
204
- jwtHeaderFromJwtSigner
205
- } from "@openid4vc/oauth2";
206
- async function createJarAuthorizationRequest(options) {
207
- const { jwtSigner, jweEncryptor, authorizationRequestPayload, requestUri, callbacks } = options;
208
- let authorizationRequestJwt;
209
- let encryptionJwk;
210
- const { jwt, signerJwk } = await callbacks.signJwt(jwtSigner, {
211
- header: { ...jwtHeaderFromJwtSigner(jwtSigner), typ: "oauth-authz-req+jwt" },
212
- payload: { ...options.additionalJwtPayload, ...authorizationRequestPayload }
213
- });
214
- authorizationRequestJwt = jwt;
215
- if (jweEncryptor) {
216
- const encryptionResult = await callbacks.encryptJwe(jweEncryptor, authorizationRequestJwt);
217
- authorizationRequestJwt = encryptionResult.jwe;
218
- encryptionJwk = encryptionResult.encryptionJwk;
219
- }
220
- const client_id = authorizationRequestPayload.client_id;
221
- const jarAuthorizationRequest = requestUri ? { client_id, request_uri: requestUri } : { client_id, request: authorizationRequestJwt };
222
- return { jarAuthorizationRequest, signerJwk, encryptionJwk, authorizationRequestJwt };
152
+ // src/authorization-request/z-authorization-request-dc-api.ts
153
+ var zOpenid4vpAuthorizationRequestDcApi = zOpenid4vpAuthorizationRequest.pick({
154
+ client_id: true,
155
+ response_type: true,
156
+ response_mode: true,
157
+ nonce: true,
158
+ presentation_definition: true,
159
+ client_metadata: true,
160
+ transaction_data: true,
161
+ dcql_query: true,
162
+ trust_chain: true
163
+ }).extend({
164
+ client_id: z5.optional(z5.string()),
165
+ expected_origins: z5.array(z5.string()).optional(),
166
+ response_mode: z5.enum(["dc_api", "dc_api.jwt", "w3c_dc_api.jwt", "w3c_dc_api"]),
167
+ client_id_scheme: z5.enum([
168
+ "pre-registered",
169
+ "redirect_uri",
170
+ "entity_id",
171
+ "did",
172
+ "verifier_attestation",
173
+ "x509_san_dns",
174
+ "x509_san_uri"
175
+ ]).optional()
176
+ }).strip();
177
+ function isOpenid4vpAuthorizationRequestDcApi(request) {
178
+ 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";
223
179
  }
224
180
 
225
- // src/authorization-request/validate-authorization-request.ts
181
+ // src/version.ts
226
182
  import { Oauth2ErrorCodes, Oauth2ServerErrorResponseError } from "@openid4vc/oauth2";
227
- import { zHttpsUrl } from "@openid4vc/utils";
228
- var validateOpenid4vpAuthorizationRequestPayload = (options) => {
229
- const { params, walletVerificationOptions } = options;
230
- if (!params.redirect_uri && !params.response_uri) {
231
- throw new Oauth2ServerErrorResponseError({
232
- error: Oauth2ErrorCodes.InvalidRequest,
233
- error_description: `Missing required 'redirect_uri' or 'response_uri' in openid4vp authorization request.`
234
- });
183
+
184
+ // src/client-identifier-scheme/z-client-id-scheme.ts
185
+ import { z as z6 } from "zod";
186
+ var zClientIdScheme = z6.enum([
187
+ "pre-registered",
188
+ "redirect_uri",
189
+ "https",
190
+ "verifier_attestation",
191
+ "did",
192
+ "x509_san_dns",
193
+ "x509_san_uri",
194
+ "web-origin"
195
+ ]);
196
+
197
+ // src/version.ts
198
+ function parseAuthorizationRequestVersion(request) {
199
+ const requirements = [];
200
+ if (isOpenid4vpAuthorizationRequestDcApi(request) && (request.response_mode === "w3c_dc_api" || request.response_mode === "w3c_dc_api.jwt")) {
201
+ requirements.push(["<", 23]);
202
+ requirements.push([">=", 21]);
235
203
  }
236
- if (params.response_uri && !["direct_post", "direct_post.jwt"].find((mode) => mode === params.response_mode)) {
237
- throw new Oauth2ServerErrorResponseError({
238
- error: Oauth2ErrorCodes.InvalidRequest,
239
- error_description: `The 'response_mode' parameter MUST be 'direct_post' or 'direct_post.jwt' when 'response_uri' is provided. Current: ${params.response_mode}`
240
- });
204
+ if (isOpenid4vpAuthorizationRequestDcApi(request) && request.response_mode === "dc_api" || request.response_mode === "dc_api.jwt") {
205
+ requirements.push([">=", 23]);
241
206
  }
242
- if ([params.presentation_definition_uri, params.presentation_definition, params.dcql_query, params.scope].filter(
243
- Boolean
244
- ).length > 1) {
245
- throw new Oauth2ServerErrorResponseError({
246
- error: Oauth2ErrorCodes.InvalidRequest,
247
- 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."
248
- });
207
+ if (isOpenid4vpAuthorizationRequestDcApi(request) && (request.transaction_data || request.dcql_query)) {
208
+ requirements.push([">=", 23]);
249
209
  }
250
- if (params.request_uri_method && !params.request_uri) {
251
- throw new Oauth2ServerErrorResponseError({
252
- error: Oauth2ErrorCodes.InvalidRequest,
253
- error_description: 'The "request_uri_method" parameter MUST NOT be present in the authorization request if the "request_uri" parameter is not present.'
254
- });
210
+ if (request.dcql_query) {
211
+ requirements.push([">=", 22]);
255
212
  }
256
- if (params.request_uri_method && !["GET", "POST"].includes(params.request_uri_method)) {
257
- throw new Oauth2ServerErrorResponseError({
258
- error: Oauth2ErrorCodes.InvalidRequestUriMethod,
259
- error_description: `The 'request_uri_method' parameter MUST be 'GET' or 'POST'. Current: ${params.request_uri_method}`
260
- });
213
+ if (request.transaction_data) {
214
+ requirements.push([">=", 22]);
261
215
  }
262
- if (params.trust_chain && !zHttpsUrl.safeParse(params.client_id).success) {
263
- throw new Oauth2ServerErrorResponseError({
264
- error: Oauth2ErrorCodes.InvalidRequest,
265
- 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://.'
266
- });
216
+ if (request.client_id_scheme) {
217
+ requirements.push(["<", 22]);
267
218
  }
268
- if (walletVerificationOptions?.expectedNonce && !params.wallet_nonce) {
269
- throw new Oauth2ServerErrorResponseError({
270
- error: Oauth2ErrorCodes.InvalidRequest,
271
- error_description: 'The "wallet_nonce" parameter MUST be present in the authorization request when the "expectedNonce" parameter is provided.'
272
- });
219
+ if (request.client_id) {
220
+ const colonIndex = request.client_id.indexOf(":");
221
+ const schemePart = request.client_id.substring(0, colonIndex);
222
+ const parsedScheme = zClientIdScheme.safeParse(schemePart);
223
+ if (parsedScheme.success && parsedScheme.data !== "did" && parsedScheme.data !== "https") {
224
+ requirements.push([">=", 22]);
225
+ }
273
226
  }
274
- if (walletVerificationOptions?.expectedNonce !== params.wallet_nonce) {
275
- throw new Oauth2ServerErrorResponseError({
276
- error: Oauth2ErrorCodes.InvalidRequest,
277
- error_description: 'The "wallet_nonce" parameter MUST match the "expectedNonce" parameter when the "expectedNonce" parameter is provided.'
278
- });
227
+ if (!request.client_id) {
228
+ requirements.push([">=", 21]);
279
229
  }
280
- if (params.client_id.startsWith("web-origin:")) {
230
+ if ("client_metadata_uri" in request) {
231
+ requirements.push(["<", 21]);
232
+ }
233
+ if (isOpenid4vpAuthorizationRequestDcApi(request)) {
234
+ requirements.push([">=", 21]);
235
+ }
236
+ if ("request_uri_method" in request || "wallet_nonce" in request) {
237
+ requirements.push([">=", 21]);
238
+ }
239
+ if (request.client_id_scheme === "verifier_attestation") {
240
+ requirements.push([">=", 20]);
241
+ }
242
+ if (request.client_id_scheme === "x509_san_dns" || request.client_id_scheme === "x509_san_uri") {
243
+ requirements.push([">=", 19]);
244
+ }
245
+ const lessThanVersions = requirements.filter(([operator]) => operator === "<").map(([_, version]) => version);
246
+ const greaterThanVersions = requirements.filter(([operator]) => operator === ">=").map(([_, version]) => version);
247
+ const highestPossibleVersion = lessThanVersions.length > 0 ? Math.max(Math.min(...lessThanVersions) - 1, 18) : 24;
248
+ const lowestRequiredVersion = greaterThanVersions.length > 0 ? Math.max(...greaterThanVersions) : 18;
249
+ if (lowestRequiredVersion > highestPossibleVersion) {
281
250
  throw new Oauth2ServerErrorResponseError({
282
251
  error: Oauth2ErrorCodes.InvalidRequest,
283
- 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}`
252
+ error_description: "Could not infer openid4vp version from the openid4vp request payload."
284
253
  });
285
254
  }
286
- };
255
+ return highestPossibleVersion;
256
+ }
287
257
 
288
- // src/authorization-request/validate-authorization-request-dc-api.ts
289
- import { Oauth2ErrorCodes as Oauth2ErrorCodes2, Oauth2ServerErrorResponseError as Oauth2ServerErrorResponseError2 } from "@openid4vc/oauth2";
290
- var validateOpenid4vpAuthorizationRequestDcApiPayload = (options) => {
291
- const { params, isJarRequest, disableOriginValidation, origin } = options;
292
- if (isJarRequest && !params.expected_origins) {
293
- throw new Oauth2ServerErrorResponseError2({
294
- error: Oauth2ErrorCodes2.InvalidRequest,
295
- error_description: `The 'expected_origins' parameter MUST be present when using the dc_api response mode in combinaction with jar.`
296
- });
297
- }
298
- if ([params.presentation_definition, params.dcql_query].filter(Boolean).length !== 1) {
299
- throw new Oauth2ServerErrorResponseError2({
300
- error: Oauth2ErrorCodes2.InvalidRequest,
301
- error_description: "Exactly one of the following parameters MUST be present in the Authorization Request: dcql_query or presentation_definition"
302
- });
258
+ // src/client-identifier-scheme/parse-client-identifier-scheme.ts
259
+ function getOpenid4vpClientId(options) {
260
+ const version = parseAuthorizationRequestVersion(options.authorizationRequestPayload);
261
+ if (version < 22) {
262
+ return getLegacyClientId(options);
303
263
  }
304
- if (params.expected_origins && !disableOriginValidation) {
305
- if (!origin) {
264
+ if (isOpenid4vpAuthorizationRequestDcApi(options.authorizationRequestPayload)) {
265
+ if (!options.origin) {
306
266
  throw new Oauth2ServerErrorResponseError2({
307
267
  error: Oauth2ErrorCodes2.InvalidRequest,
308
- error_description: `Failed to validate the 'origin' of the authorization request. The 'origin' was not provided.`
268
+ error_description: "Failed to parse client identifier. 'origin' is required for requests with response_mode 'dc_api' and 'dc_api.jwt'"
309
269
  });
310
270
  }
311
- if (params.expected_origins && !params.expected_origins.includes(origin)) {
271
+ if (!options.jar || !options.authorizationRequestPayload.client_id) return `web-origin:${options.origin}`;
272
+ return options.authorizationRequestPayload.client_id;
273
+ }
274
+ return options.authorizationRequestPayload.client_id;
275
+ }
276
+ function getLegacyClientId(options) {
277
+ const legacyClientIdScheme = options.authorizationRequestPayload.client_id_scheme ?? "pre-registered";
278
+ const clientIdScheme = legacyClientIdScheme === "entity_id" ? "https" : legacyClientIdScheme;
279
+ if (isOpenid4vpAuthorizationRequestDcApi(options.authorizationRequestPayload)) {
280
+ if (!options.origin) {
312
281
  throw new Oauth2ServerErrorResponseError2({
313
282
  error: Oauth2ErrorCodes2.InvalidRequest,
314
- error_description: `The 'expected_origins' parameter MUST include the origin of the authorization request. Current: ${params.expected_origins.join(", ")}`
283
+ error_description: "Failed to parse client identifier. 'origin' is required for requests with response_mode 'dc_api' and 'dc_api.jwt'"
315
284
  });
316
285
  }
286
+ if (!options.jar || !options.authorizationRequestPayload.client_id) return `web-origin:${options.origin}`;
287
+ return `${clientIdScheme}:${options.authorizationRequestPayload.client_id}`;
317
288
  }
318
- };
319
-
320
- // src/authorization-request/z-authorization-request.ts
321
- import { zHttpsUrl as zHttpsUrl3 } from "@openid4vc/utils";
322
- import { z as z7 } from "zod";
323
-
324
- // src/models/z-client-metadata.ts
325
- import { zJwkSet } from "@openid4vc/oauth2";
326
- import { zHttpsUrl as zHttpsUrl2 } from "@openid4vc/utils";
327
- import { z as z6 } from "zod";
328
-
329
- // src/models/z-vp-formats-supported.ts
330
- import { z as z5 } from "zod";
331
- var zVpFormatsSupported = z5.record(
332
- z5.string(),
333
- z5.object({
334
- alg_values_supported: z5.optional(z5.array(z5.string()))
335
- }).passthrough()
336
- );
337
-
338
- // src/models/z-client-metadata.ts
339
- var zClientMetadata = z6.object({
340
- jwks: z6.optional(zJwkSet),
341
- vp_formats: z6.optional(zVpFormatsSupported),
342
- ...zJarmClientMetadata.shape,
343
- logo_uri: zHttpsUrl2.optional(),
344
- client_name: z6.string().optional()
345
- }).passthrough();
346
-
347
- // src/authorization-request/z-authorization-request.ts
348
- var zOpenid4vpAuthorizationRequest = z7.object({
349
- response_type: z7.literal("vp_token"),
350
- client_id: z7.string(),
351
- redirect_uri: zHttpsUrl3.optional(),
352
- response_uri: zHttpsUrl3.optional(),
353
- request_uri: zHttpsUrl3.optional(),
354
- request_uri_method: z7.optional(z7.string()),
355
- response_mode: z7.enum(["direct_post", "direct_post.jwt"]).optional(),
356
- nonce: z7.string(),
357
- wallet_nonce: z7.string().optional(),
358
- scope: z7.string().optional(),
359
- presentation_definition: z7.record(z7.any()).optional(),
360
- presentation_definition_uri: zHttpsUrl3.optional(),
361
- dcql_query: z7.record(z7.any()).optional(),
362
- client_metadata: zClientMetadata.optional(),
363
- client_metadata_uri: zHttpsUrl3.optional(),
364
- state: z7.string().optional(),
365
- transaction_data: z7.array(z7.string()).optional(),
366
- trust_chain: z7.unknown().optional(),
367
- client_id_scheme: z7.enum([
368
- "pre-registered",
369
- "redirect_uri",
370
- "entity_id",
371
- "did",
372
- "verifier_attestation",
373
- "x509_san_dns",
374
- "x509_san_uri"
375
- ]).optional()
376
- }).passthrough();
377
-
378
- // src/authorization-request/z-authorization-request-dc-api.ts
379
- import { z as z8 } from "zod";
380
- var zOpenid4vpAuthorizationRequestDcApi = zOpenid4vpAuthorizationRequest.pick({
381
- client_id: true,
382
- response_type: true,
383
- response_mode: true,
384
- nonce: true,
385
- presentation_definition: true,
386
- client_metadata: true,
387
- transaction_data: true,
388
- dcql_query: true,
389
- trust_chain: true
390
- }).extend({
391
- client_id: z8.optional(z8.string()),
392
- expected_origins: z8.array(z8.string()).optional(),
393
- response_mode: z8.enum(["dc_api", "dc_api.jwt", "w3c_dc_api.jwt", "w3c_dc_api"]),
394
- client_id_scheme: z8.enum([
395
- "pre-registered",
396
- "redirect_uri",
397
- "entity_id",
398
- "did",
399
- "verifier_attestation",
400
- "x509_san_dns",
401
- "x509_san_uri"
402
- ]).optional()
403
- }).strip();
404
- function isOpenid4vpAuthorizationRequestDcApi(request) {
405
- 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";
289
+ if (clientIdScheme === "https" || clientIdScheme === "did") {
290
+ return options.authorizationRequestPayload.client_id;
291
+ }
292
+ if (clientIdScheme === "pre-registered") {
293
+ return options.authorizationRequestPayload.client_id;
294
+ }
295
+ return `${clientIdScheme}:${options.authorizationRequestPayload.client_id}`;
406
296
  }
407
-
408
- // src/authorization-request/create-authorization-request.ts
409
- async function createOpenid4vpAuthorizationRequest(options) {
410
- const { jar, scheme = "openid4vp://", wallet, callbacks } = options;
411
- let additionalJwtPayload;
412
- let authorizationRequestPayload;
413
- if (isOpenid4vpAuthorizationRequestDcApi(options.authorizationRequestPayload)) {
414
- authorizationRequestPayload = parseWithErrorHandling2(
415
- zOpenid4vpAuthorizationRequestDcApi,
416
- options.authorizationRequestPayload,
417
- "Invalid authorization request. Could not parse openid4vp dc_api authorization request."
418
- );
419
- if (jar && !authorizationRequestPayload.expected_origins) {
420
- throw new Oauth2Error4(
421
- `The 'expected_origins' parameter MUST be present when using the dc_api response mode in combination with jar.`
422
- );
423
- }
424
- validateOpenid4vpAuthorizationRequestDcApiPayload({
425
- params: authorizationRequestPayload,
426
- isJarRequest: Boolean(jar),
427
- disableOriginValidation: true
428
- });
429
- } else {
430
- authorizationRequestPayload = parseWithErrorHandling2(
431
- zOpenid4vpAuthorizationRequest,
432
- options.authorizationRequestPayload,
433
- "Invalid authorization request. Could not parse openid4vp authorization request."
434
- );
435
- validateOpenid4vpAuthorizationRequestPayload({
436
- params: authorizationRequestPayload,
437
- walletVerificationOptions: wallet
297
+ function parseClientIdentifier(options, parserConfig) {
298
+ const { authorizationRequestPayload, jar } = options;
299
+ const parserConfigWithDefaults = {
300
+ supportedSchemes: parserConfig?.supportedSchemes || Object.values(zClientIdScheme.options)
301
+ };
302
+ const clientId = getOpenid4vpClientId(options);
303
+ const colonIndex = clientId.indexOf(":");
304
+ if (colonIndex === -1) {
305
+ return {
306
+ scheme: "pre-registered",
307
+ identifier: clientId,
308
+ originalValue: clientId,
309
+ clientMetadata: authorizationRequestPayload.client_metadata
310
+ };
311
+ }
312
+ const schemePart = clientId.substring(0, colonIndex);
313
+ const identifierPart = clientId.substring(colonIndex + 1);
314
+ if (!parserConfigWithDefaults.supportedSchemes.includes(schemePart)) {
315
+ throw new Oauth2ServerErrorResponseError2({
316
+ error: Oauth2ErrorCodes2.InvalidRequest,
317
+ error_description: `Unsupported client identifier scheme. ${schemePart} is not supported.`
438
318
  });
439
319
  }
440
- if (jar) {
441
- if (!jar.additionalJwtPayload?.aud) {
442
- additionalJwtPayload = { ...jar.additionalJwtPayload, aud: jar.requestUri };
320
+ const scheme = schemePart;
321
+ if (scheme === "https") {
322
+ if (!clientId.startsWith("https://") && !(getGlobalConfig().allowInsecureUrls && clientId.startsWith("http://"))) {
323
+ throw new Oauth2ServerErrorResponseError2({
324
+ error: Oauth2ErrorCodes2.InvalidRequest,
325
+ error_description: "Invalid client identifier. Client identifier must start with https:// or http:// if allowInsecureUrls is true."
326
+ });
443
327
  }
444
- const jarResult = await createJarAuthorizationRequest({
445
- ...jar,
446
- authorizationRequestPayload,
447
- additionalJwtPayload,
448
- callbacks
449
- });
450
- const url2 = new URL(scheme);
451
- url2.search = `?${new URLSearchParams([
452
- ...url2.searchParams.entries(),
453
- ...objectToQueryParams(jarResult.jarAuthorizationRequest).entries()
454
- ]).toString()}`;
455
328
  return {
456
- authorizationRequestPayload,
457
- authorizationRequestObject: jarResult.jarAuthorizationRequest,
458
- authorizationRequest: url2.toString(),
459
- jar: { ...jar, ...jarResult }
329
+ scheme,
330
+ identifier: clientId,
331
+ originalValue: clientId,
332
+ trustChain: authorizationRequestPayload.trust_chain
460
333
  };
461
334
  }
462
- const url = new URL(scheme);
463
- url.search = `?${new URLSearchParams([
464
- ...url.searchParams.entries(),
465
- ...objectToQueryParams(authorizationRequestPayload).entries()
466
- ]).toString()}`;
467
- return {
468
- authorizationRequestPayload,
469
- authorizationRequestObject: authorizationRequestPayload,
470
- authorizationRequest: url.toString(),
471
- jar: void 0
472
- };
473
- }
474
-
475
- // src/authorization-request/parse-authorization-request-params.ts
476
- import { decodeJwt as decodeJwt2 } from "@openid4vc/oauth2";
477
- import { URL as URL2 } from "@openid4vc/utils";
478
- import { parseWithErrorHandling as parseWithErrorHandling3 } from "@openid4vc/utils";
479
- import z10 from "zod";
480
-
481
- // src/jar/z-jar-authorization-request.ts
482
- import { Oauth2ServerErrorResponseError as Oauth2ServerErrorResponseError3 } from "@openid4vc/oauth2";
483
- import { zHttpsUrl as zHttpsUrl4 } from "@openid4vc/utils";
484
- import { z as z9 } from "zod";
485
- var zJarAuthorizationRequest = z9.object({
486
- request: z9.optional(z9.string()),
487
- request_uri: z9.optional(zHttpsUrl4),
488
- request_uri_method: z9.optional(z9.string()),
489
- client_id: z9.optional(z9.string())
490
- }).passthrough();
491
- function validateJarRequestParams(options) {
492
- const { jarRequestParams } = options;
493
- if (jarRequestParams.request && jarRequestParams.request_uri) {
494
- throw new Oauth2ServerErrorResponseError3({
495
- error: "invalid_request_object",
496
- error_description: "request and request_uri cannot both be present in a JAR request"
497
- });
498
- }
499
- if (!jarRequestParams.request && !jarRequestParams.request_uri) {
500
- throw new Oauth2ServerErrorResponseError3({
501
- error: "invalid_request_object",
502
- error_description: "request or request_uri must be present"
503
- });
335
+ if (scheme === "redirect_uri") {
336
+ if (jar) {
337
+ throw new Oauth2ServerErrorResponseError2({
338
+ error: Oauth2ErrorCodes2.InvalidRequest,
339
+ error_description: 'Using client identifier scheme "redirect_uri" the request MUST NOT be signed.'
340
+ });
341
+ }
342
+ if (isOpenid4vpAuthorizationRequestDcApi(authorizationRequestPayload)) {
343
+ throw new Oauth2ServerErrorResponseError2({
344
+ error: Oauth2ErrorCodes2.InvalidRequest,
345
+ error_description: `The client identifier scheme 'redirect_uri' is not supported when using the dc_api response mode.`
346
+ });
347
+ }
348
+ return {
349
+ scheme,
350
+ identifier: identifierPart,
351
+ originalValue: clientId,
352
+ redirectUri: authorizationRequestPayload.redirect_uri ?? authorizationRequestPayload.response_uri
353
+ };
504
354
  }
505
- return jarRequestParams;
506
- }
507
- function isJarAuthorizationRequest(request) {
508
- return "request" in request || "request_uri" in request;
509
- }
510
-
511
- // src/authorization-request/parse-authorization-request-params.ts
512
- function parseOpenid4vpAuthorizationRequestPayload(options) {
513
- const { authorizationRequest } = options;
514
- let provided = "params";
515
- let params;
516
- if (typeof authorizationRequest === "string") {
517
- if (authorizationRequest.includes("://")) {
518
- const url = new URL2(authorizationRequest);
519
- params = Object.fromEntries(url.searchParams);
520
- provided = "uri";
521
- } else {
522
- const decoded = decodeJwt2({ jwt: authorizationRequest });
523
- params = decoded.payload;
524
- provided = "jwt";
355
+ if (scheme === "did") {
356
+ if (!jar) {
357
+ throw new Oauth2ServerErrorResponseError2({
358
+ error: Oauth2ErrorCodes2.InvalidRequest,
359
+ error_description: 'Using client identifier scheme "did" requires a signed JAR request.'
360
+ });
525
361
  }
526
- } else {
527
- params = authorizationRequest;
362
+ if (!clientId.startsWith("did:")) {
363
+ throw new Oauth2ServerErrorResponseError2({
364
+ error: Oauth2ErrorCodes2.InvalidRequest,
365
+ error_description: "Invalid client identifier. Client identifier must start with 'did:'"
366
+ });
367
+ }
368
+ if (!jar.signer.publicJwk.kid) {
369
+ throw new Oauth2ServerErrorResponseError2({
370
+ error: Oauth2ErrorCodes2.InvalidRequest,
371
+ error_description: `Missing required 'kid' for client identifier scheme: did`
372
+ });
373
+ }
374
+ if (!jar.signer.publicJwk.kid?.startsWith(clientId)) {
375
+ throw new Oauth2ServerErrorResponseError2({
376
+ error: Oauth2ErrorCodes2.InvalidRequest,
377
+ error_description: 'With client identifier scheme "did" the JAR request must be signed by the same DID as the client identifier.'
378
+ });
379
+ }
380
+ return {
381
+ scheme,
382
+ identifier: clientId,
383
+ originalValue: clientId,
384
+ didUrl: jar.signer.publicJwk.kid
385
+ };
528
386
  }
529
- const parsedRequest = parseWithErrorHandling3(
530
- z10.union([zOpenid4vpAuthorizationRequest, zJarAuthorizationRequest, zOpenid4vpAuthorizationRequestDcApi]),
531
- params
532
- );
533
- if (isJarAuthorizationRequest(parsedRequest)) {
387
+ if (scheme === "x509_san_dns" || scheme === "x509_san_uri") {
388
+ if (!jar) {
389
+ throw new Oauth2ServerErrorResponseError2({
390
+ error: Oauth2ErrorCodes2.InvalidRequest,
391
+ error_description: 'Using client identifier scheme "x509_san_dns" or "x509_san_uri" requires a signed JAR request.'
392
+ });
393
+ }
394
+ if (jar.signer.method !== "x5c") {
395
+ throw new Oauth2ServerErrorResponseError2({
396
+ error: Oauth2ErrorCodes2.InvalidRequest,
397
+ error_description: "Something went wrong. The JWT signer method is not x5c but the client identifier scheme is x509_san_dns."
398
+ });
399
+ }
400
+ if (scheme === "x509_san_dns") {
401
+ if (!options.callbacks.getX509CertificateMetadata) {
402
+ throw new Oauth2ServerErrorResponseError2(
403
+ {
404
+ error: Oauth2ErrorCodes2.ServerError
405
+ },
406
+ {
407
+ internalMessage: "Missing required 'getX509CertificateMetadata' callback for verification of 'x509_san_dns' client id scheme"
408
+ }
409
+ );
410
+ }
411
+ const { sanDnsNames } = options.callbacks.getX509CertificateMetadata(jar.signer.x5c[0]);
412
+ if (!sanDnsNames.includes(identifierPart)) {
413
+ throw new Oauth2ServerErrorResponseError2({
414
+ error: Oauth2ErrorCodes2.InvalidRequest,
415
+ error_description: `Invalid client identifier. One of the leaf certificates san dns names [${sanDnsNames.join(", ")}] must match the client identifier '${identifierPart}'. `
416
+ });
417
+ }
418
+ if (!isOpenid4vpAuthorizationRequestDcApi(authorizationRequestPayload)) {
419
+ const uri = authorizationRequestPayload.redirect_uri ?? authorizationRequestPayload.response_uri;
420
+ if (!uri || new URL2(uri).hostname !== identifierPart) {
421
+ throw new Oauth2ServerErrorResponseError2({
422
+ error: Oauth2ErrorCodes2.InvalidRequest,
423
+ 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."
424
+ });
425
+ }
426
+ }
427
+ } else if (scheme === "x509_san_uri") {
428
+ if (!options.callbacks.getX509CertificateMetadata) {
429
+ throw new Oauth2ServerErrorResponseError2(
430
+ {
431
+ error: Oauth2ErrorCodes2.ServerError
432
+ },
433
+ {
434
+ internalMessage: "Missing required 'getX509CertificateMetadata' callback for verification of 'x509_san_uri' client id scheme"
435
+ }
436
+ );
437
+ }
438
+ const { sanUriNames } = options.callbacks.getX509CertificateMetadata(jar.signer.x5c[0]);
439
+ if (!sanUriNames.includes(identifierPart)) {
440
+ throw new Oauth2ServerErrorResponseError2({
441
+ error: Oauth2ErrorCodes2.InvalidRequest,
442
+ error_description: `Invalid client identifier. One of the leaf certificates san uri names [${sanUriNames.join(", ")}] must match the client identifier '${identifierPart}'.`
443
+ });
444
+ }
445
+ if (!isOpenid4vpAuthorizationRequestDcApi(authorizationRequestPayload)) {
446
+ const uri = authorizationRequestPayload.redirect_uri || authorizationRequestPayload.response_uri;
447
+ if (!uri || uri !== identifierPart) {
448
+ throw new Oauth2ServerErrorResponseError2({
449
+ error: Oauth2ErrorCodes2.InvalidRequest,
450
+ error_description: "The redirect_uri value MUST match the Client Identifier without the prefix x509_san_uri"
451
+ });
452
+ }
453
+ }
454
+ }
534
455
  return {
535
- type: "jar",
536
- provided,
537
- params: parsedRequest
456
+ scheme,
457
+ identifier: identifierPart,
458
+ originalValue: clientId,
459
+ x5c: jar.signer.x5c
538
460
  };
539
461
  }
540
- if (isOpenid4vpAuthorizationRequestDcApi(parsedRequest)) {
462
+ if (scheme === "web-origin") {
541
463
  return {
542
- type: "openid4vp_dc_api",
543
- provided,
544
- params: parsedRequest
464
+ scheme,
465
+ identifier: identifierPart,
466
+ originalValue: clientId,
467
+ clientMetadata: authorizationRequestPayload.client_metadata
545
468
  };
546
469
  }
470
+ if (scheme === "verifier_attestation") {
471
+ if (!jar) {
472
+ throw new Oauth2ServerErrorResponseError2({
473
+ error: Oauth2ErrorCodes2.InvalidRequest,
474
+ error_description: 'Using client identifier scheme "verifier_attestation" requires a signed JAR request.'
475
+ });
476
+ }
477
+ }
547
478
  return {
548
- type: "openid4vp",
549
- provided,
550
- params: parsedRequest
479
+ scheme,
480
+ identifier: identifierPart,
481
+ originalValue: clientId
551
482
  };
552
483
  }
553
484
 
554
- // src/authorization-request/resolve-authorization-request.ts
555
- import { Oauth2ErrorCodes as Oauth2ErrorCodes9, Oauth2ServerErrorResponseError as Oauth2ServerErrorResponseError10 } from "@openid4vc/oauth2";
556
- import { parseWithErrorHandling as parseWithErrorHandling4 } from "@openid4vc/utils";
557
- import z14 from "zod";
485
+ // src/jarm/jarm-authorization-response/verify-jarm-authorization-response.ts
486
+ import {
487
+ Oauth2Error as Oauth2Error3,
488
+ decodeJwt,
489
+ jwtSignerFromJwt,
490
+ zCompactJwe,
491
+ zCompactJwt,
492
+ zJwtHeader as zJwtHeader2
493
+ } from "@openid4vc/oauth2";
494
+ import z8 from "zod";
558
495
 
559
- // src/client-identifier-scheme/parse-client-identifier-scheme.ts
560
- import { Oauth2ErrorCodes as Oauth2ErrorCodes4, Oauth2ServerErrorResponseError as Oauth2ServerErrorResponseError5, getGlobalConfig } from "@openid4vc/oauth2";
561
- import { URL as URL3 } from "@openid4vc/utils";
496
+ // src/jarm/jarm-extract-jwks.ts
497
+ function extractJwksFromClientMetadata(clientMetadata) {
498
+ const parsed = zJarmClientMetadataParsed.parse(clientMetadata);
499
+ const encryptionAlg = parsed.client_metadata.authorization_encrypted_response_enc;
500
+ const signingAlg = parsed.client_metadata.authorization_signed_response_alg;
501
+ 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
502
+ clientMetadata.jwks.keys?.[0];
503
+ 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
504
+ clientMetadata.jwks.keys?.[0];
505
+ return { encJwk, sigJwk };
506
+ }
562
507
 
563
- // src/version.ts
564
- import { Oauth2ErrorCodes as Oauth2ErrorCodes3, Oauth2ServerErrorResponseError as Oauth2ServerErrorResponseError4 } from "@openid4vc/oauth2";
565
- function parseAuthorizationRequestVersion(request) {
566
- const requirements = [];
567
- if (isOpenid4vpAuthorizationRequestDcApi(request) && (request.response_mode === "w3c_dc_api" || request.response_mode === "w3c_dc_api.jwt")) {
568
- requirements.push(["<", 23]);
569
- requirements.push([">=", 21]);
570
- }
571
- if (isOpenid4vpAuthorizationRequestDcApi(request) && request.response_mode === "dc_api" || request.response_mode === "dc_api.jwt") {
572
- requirements.push([">=", 23]);
508
+ // src/jarm/jarm-authorization-response/jarm-validate-authorization-response.ts
509
+ import { Oauth2Error as Oauth2Error2 } from "@openid4vc/oauth2";
510
+ import { dateToSeconds } from "@openid4vc/utils";
511
+
512
+ // src/jarm/jarm-authorization-response/z-jarm-authorization-response.ts
513
+ import { zJwtHeader, zJwtPayload } from "@openid4vc/oauth2";
514
+ import { z as z7 } from "zod";
515
+ var zJarmHeader = z7.object({ ...zJwtHeader.shape, apu: z7.string().optional(), apv: z7.string().optional() });
516
+ var zJarmAuthorizationResponse = z7.object({
517
+ /**
518
+ * iss: The issuer URL of the authorization server that created the response
519
+ * aud: The client_id of the client the response is intended for
520
+ * exp: The expiration time of the JWT. A maximum JWT lifetime of 10 minutes is RECOMMENDED.
521
+ */
522
+ ...zJwtPayload.shape,
523
+ ...zJwtPayload.pick({ iss: true, aud: true, exp: true }).required().shape,
524
+ state: z7.optional(z7.string())
525
+ }).passthrough();
526
+ var zJarmAuthorizationResponseEncryptedOnly = z7.object({
527
+ ...zJwtPayload.shape,
528
+ state: z7.optional(z7.string())
529
+ }).passthrough();
530
+
531
+ // src/jarm/jarm-authorization-response/jarm-validate-authorization-response.ts
532
+ var jarmAuthorizationResponseValidate = (options) => {
533
+ const { expectedClientId, authorizationResponse } = options;
534
+ if (!zJarmAuthorizationResponse.safeParse(authorizationResponse).success) {
535
+ return;
573
536
  }
574
- if (isOpenid4vpAuthorizationRequestDcApi(request) && (request.transaction_data || request.dcql_query)) {
575
- requirements.push([">=", 23]);
537
+ if (expectedClientId !== authorizationResponse.aud) {
538
+ throw new Oauth2Error2(
539
+ `Invalid 'aud' claim in JARM authorization response. Expected '${expectedClientId}' received '${JSON.stringify(authorizationResponse.aud)}'.`
540
+ );
576
541
  }
577
- if (request.dcql_query) {
578
- requirements.push([">=", 22]);
542
+ if (authorizationResponse.exp !== void 0 && authorizationResponse.exp < dateToSeconds()) {
543
+ throw new Oauth2Error2("Jarm auth response is expired.");
579
544
  }
580
- if (request.transaction_data) {
581
- requirements.push([">=", 22]);
545
+ };
546
+
547
+ // src/jarm/jarm-authorization-response/verify-jarm-authorization-response.ts
548
+ var decryptJarmAuthorizationResponseJwt = async (options) => {
549
+ const { jarmAuthorizationResponseJwt, callbacks, authorizationRequestPayload } = options;
550
+ const encryptionJwk = authorizationRequestPayload.client_metadata?.jwks ? extractJwksFromClientMetadata({
551
+ ...authorizationRequestPayload.client_metadata,
552
+ jwks: authorizationRequestPayload.client_metadata.jwks
553
+ }).encJwk : void 0;
554
+ const result = await callbacks.decryptJwe(jarmAuthorizationResponseJwt, { jwk: encryptionJwk });
555
+ if (!result.decrypted) {
556
+ throw new Oauth2Error3("Failed to decrypt jarm auth response.");
582
557
  }
583
- if (request.client_id_scheme) {
584
- requirements.push(["<", 22]);
558
+ return result.payload;
559
+ };
560
+ async function verifyJarmAuthorizationResponse(options) {
561
+ const { jarmAuthorizationResponseJwt, callbacks, expectedClientId, authorizationRequestPayload } = options;
562
+ const requestDataIsEncrypted = zCompactJwe.safeParse(jarmAuthorizationResponseJwt).success;
563
+ const decryptedRequestData = requestDataIsEncrypted ? await decryptJarmAuthorizationResponseJwt({
564
+ jarmAuthorizationResponseJwt,
565
+ callbacks,
566
+ authorizationRequestPayload
567
+ }) : jarmAuthorizationResponseJwt;
568
+ const responseIsSigned = zCompactJwt.safeParse(decryptedRequestData).success;
569
+ if (!requestDataIsEncrypted && !responseIsSigned) {
570
+ throw new Oauth2Error3("Jarm Auth Response must be either encrypted, signed, or signed and encrypted.");
585
571
  }
586
- if (request.client_id) {
587
- const colonIndex = request.client_id.indexOf(":");
588
- const schemePart = request.client_id.substring(0, colonIndex);
589
- const parsedScheme = zClientIdScheme.safeParse(schemePart);
590
- if (parsedScheme.success && parsedScheme.data !== "did" && parsedScheme.data !== "https") {
591
- requirements.push([">=", 22]);
572
+ let jarmAuthorizationResponse;
573
+ if (responseIsSigned) {
574
+ const { header: jwsProtectedHeader, payload: jwsPayload } = decodeJwt({
575
+ jwt: decryptedRequestData,
576
+ headerSchema: z8.object({ ...zJwtHeader2.shape, kid: z8.string() })
577
+ });
578
+ const response = zJarmAuthorizationResponse.parse(jwsPayload);
579
+ const jwtSigner = jwtSignerFromJwt({ header: jwsProtectedHeader, payload: jwsPayload });
580
+ const verificationResult = await options.callbacks.verifyJwt(jwtSigner, {
581
+ compact: decryptedRequestData,
582
+ header: jwsProtectedHeader,
583
+ payload: jwsPayload
584
+ });
585
+ if (!verificationResult.verified) {
586
+ throw new Oauth2Error3("Jarm Auth Response is not valid.");
592
587
  }
588
+ jarmAuthorizationResponse = response;
589
+ } else {
590
+ const jsonRequestData = JSON.parse(decryptedRequestData);
591
+ jarmAuthorizationResponse = zJarmAuthorizationResponseEncryptedOnly.parse(jsonRequestData);
593
592
  }
594
- if (!request.client_id) {
595
- requirements.push([">=", 21]);
596
- }
597
- if ("client_metadata_uri" in request) {
598
- requirements.push(["<", 21]);
599
- }
600
- if (isOpenid4vpAuthorizationRequestDcApi(request)) {
601
- requirements.push([">=", 21]);
602
- }
603
- if ("request_uri_method" in request || "wallet_nonce" in request) {
604
- requirements.push([">=", 21]);
605
- }
606
- if (request.client_id_scheme === "verifier_attestation") {
607
- requirements.push([">=", 20]);
593
+ jarmAuthorizationResponseValidate({
594
+ expectedClientId,
595
+ authorizationResponse: jarmAuthorizationResponse
596
+ });
597
+ const type = requestDataIsEncrypted && responseIsSigned ? "SignedEncrypted" /* SignedEncrypted */ : requestDataIsEncrypted ? "Encrypted" /* Encrypted */ : "Signed" /* Signed */;
598
+ const issuer = jarmAuthorizationResponse.iss;
599
+ return { jarmAuthorizationResponse, type, issuer };
600
+ }
601
+
602
+ // src/authorization-request/create-authorization-request.ts
603
+ import { Oauth2Error as Oauth2Error4 } from "@openid4vc/oauth2";
604
+ import { URL as URL3, URLSearchParams, objectToQueryParams, parseWithErrorHandling as parseWithErrorHandling2 } from "@openid4vc/utils";
605
+
606
+ // src/jar/create-jar-authorization-request.ts
607
+ import {
608
+ jwtHeaderFromJwtSigner
609
+ } from "@openid4vc/oauth2";
610
+ async function createJarAuthorizationRequest(options) {
611
+ const { jwtSigner, jweEncryptor, authorizationRequestPayload, requestUri, callbacks } = options;
612
+ let authorizationRequestJwt;
613
+ let encryptionJwk;
614
+ const { jwt, signerJwk } = await callbacks.signJwt(jwtSigner, {
615
+ header: { ...jwtHeaderFromJwtSigner(jwtSigner), typ: "oauth-authz-req+jwt" },
616
+ payload: { ...options.additionalJwtPayload, ...authorizationRequestPayload }
617
+ });
618
+ authorizationRequestJwt = jwt;
619
+ if (jweEncryptor) {
620
+ const encryptionResult = await callbacks.encryptJwe(jweEncryptor, authorizationRequestJwt);
621
+ authorizationRequestJwt = encryptionResult.jwe;
622
+ encryptionJwk = encryptionResult.encryptionJwk;
608
623
  }
609
- if (request.client_id_scheme === "x509_san_dns" || request.client_id_scheme === "x509_san_uri") {
610
- requirements.push([">=", 19]);
624
+ const client_id = authorizationRequestPayload.client_id;
625
+ const jarAuthorizationRequest = requestUri ? { client_id, request_uri: requestUri } : { client_id, request: authorizationRequestJwt };
626
+ return { jarAuthorizationRequest, signerJwk, encryptionJwk, authorizationRequestJwt };
627
+ }
628
+
629
+ // src/authorization-request/validate-authorization-request.ts
630
+ import { Oauth2ErrorCodes as Oauth2ErrorCodes3, Oauth2ServerErrorResponseError as Oauth2ServerErrorResponseError3 } from "@openid4vc/oauth2";
631
+ import { zHttpsUrl as zHttpsUrl3 } from "@openid4vc/utils";
632
+ var validateOpenid4vpAuthorizationRequestPayload = (options) => {
633
+ const { params, walletVerificationOptions } = options;
634
+ if (!params.redirect_uri && !params.response_uri) {
635
+ throw new Oauth2ServerErrorResponseError3({
636
+ error: Oauth2ErrorCodes3.InvalidRequest,
637
+ error_description: `Missing required 'redirect_uri' or 'response_uri' in openid4vp authorization request.`
638
+ });
611
639
  }
612
- const lessThanVersions = requirements.filter(([operator]) => operator === "<").map(([_, version]) => version);
613
- const greaterThanVersions = requirements.filter(([operator]) => operator === ">=").map(([_, version]) => version);
614
- const highestPossibleVersion = lessThanVersions.length > 0 ? Math.max(Math.min(...lessThanVersions) - 1, 18) : 24;
615
- const lowestRequiredVersion = greaterThanVersions.length > 0 ? Math.max(...greaterThanVersions) : 18;
616
- if (lowestRequiredVersion > highestPossibleVersion) {
617
- throw new Oauth2ServerErrorResponseError4({
640
+ if (params.response_uri && !["direct_post", "direct_post.jwt"].find((mode) => mode === params.response_mode)) {
641
+ throw new Oauth2ServerErrorResponseError3({
618
642
  error: Oauth2ErrorCodes3.InvalidRequest,
619
- error_description: "Could not infer openid4vp version from the openid4vp request payload."
643
+ error_description: `The 'response_mode' parameter MUST be 'direct_post' or 'direct_post.jwt' when 'response_uri' is provided. Current: ${params.response_mode}`
620
644
  });
621
645
  }
622
- return highestPossibleVersion;
623
- }
624
-
625
- // src/client-identifier-scheme/parse-client-identifier-scheme.ts
626
- function getClientId(options) {
627
- const version = parseAuthorizationRequestVersion(options.authorizationRequestPayload);
628
- if (version < 22) {
629
- return getLegacyClientId(options);
646
+ if ([params.presentation_definition_uri, params.presentation_definition, params.dcql_query, params.scope].filter(
647
+ Boolean
648
+ ).length > 1) {
649
+ throw new Oauth2ServerErrorResponseError3({
650
+ error: Oauth2ErrorCodes3.InvalidRequest,
651
+ 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."
652
+ });
630
653
  }
631
- if (isOpenid4vpAuthorizationRequestDcApi(options.authorizationRequestPayload)) {
632
- if (!options.origin) {
633
- throw new Oauth2ServerErrorResponseError5({
634
- error: Oauth2ErrorCodes4.InvalidRequest,
635
- error_description: "Failed to parse client identifier. 'origin' is required for requests with response_mode 'dc_api' and 'dc_api.jwt'"
636
- });
637
- }
638
- if (!options.jar || !options.authorizationRequestPayload.client_id) return `web-origin:${options.origin}`;
639
- return options.authorizationRequestPayload.client_id;
654
+ if (params.request_uri_method && !params.request_uri) {
655
+ throw new Oauth2ServerErrorResponseError3({
656
+ error: Oauth2ErrorCodes3.InvalidRequest,
657
+ error_description: 'The "request_uri_method" parameter MUST NOT be present in the authorization request if the "request_uri" parameter is not present.'
658
+ });
640
659
  }
641
- return options.authorizationRequestPayload.client_id;
642
- }
643
- function getLegacyClientId(options) {
644
- const legacyClientIdScheme = options.authorizationRequestPayload.client_id_scheme ?? "pre-registered";
645
- const clientIdScheme = legacyClientIdScheme === "entity_id" ? "https" : legacyClientIdScheme;
646
- if (isOpenid4vpAuthorizationRequestDcApi(options.authorizationRequestPayload)) {
647
- if (!options.origin) {
648
- throw new Oauth2ServerErrorResponseError5({
649
- error: Oauth2ErrorCodes4.InvalidRequest,
650
- error_description: "Failed to parse client identifier. 'origin' is required for requests with response_mode 'dc_api' and 'dc_api.jwt'"
651
- });
652
- }
653
- if (!options.jar || !options.authorizationRequestPayload.client_id) return `web-origin:${options.origin}`;
654
- return `${clientIdScheme}:${options.authorizationRequestPayload.client_id}`;
660
+ if (params.request_uri_method && !["GET", "POST"].includes(params.request_uri_method)) {
661
+ throw new Oauth2ServerErrorResponseError3({
662
+ error: Oauth2ErrorCodes3.InvalidRequestUriMethod,
663
+ error_description: `The 'request_uri_method' parameter MUST be 'GET' or 'POST'. Current: ${params.request_uri_method}`
664
+ });
655
665
  }
656
- if (clientIdScheme === "https" || clientIdScheme === "did") {
657
- return options.authorizationRequestPayload.client_id;
666
+ if (params.trust_chain && !zHttpsUrl3.safeParse(params.client_id).success) {
667
+ throw new Oauth2ServerErrorResponseError3({
668
+ error: Oauth2ErrorCodes3.InvalidRequest,
669
+ 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://.'
670
+ });
658
671
  }
659
- if (clientIdScheme === "pre-registered") {
660
- return options.authorizationRequestPayload.client_id;
672
+ if (walletVerificationOptions?.expectedNonce && !params.wallet_nonce) {
673
+ throw new Oauth2ServerErrorResponseError3({
674
+ error: Oauth2ErrorCodes3.InvalidRequest,
675
+ error_description: 'The "wallet_nonce" parameter MUST be present in the authorization request when the "expectedNonce" parameter is provided.'
676
+ });
661
677
  }
662
- return `${clientIdScheme}:${options.authorizationRequestPayload.client_id}`;
663
- }
664
- function parseClientIdentifier(options, parserConfig) {
665
- const { authorizationRequestPayload, jar } = options;
666
- const parserConfigWithDefaults = {
667
- supportedSchemes: parserConfig?.supportedSchemes || Object.values(zClientIdScheme.options)
668
- };
669
- const clientId = getClientId(options);
670
- const colonIndex = clientId.indexOf(":");
671
- if (colonIndex === -1) {
672
- return {
673
- scheme: "pre-registered",
674
- identifier: clientId,
675
- originalValue: clientId,
676
- clientMetadata: authorizationRequestPayload.client_metadata
677
- };
678
+ if (walletVerificationOptions?.expectedNonce !== params.wallet_nonce) {
679
+ throw new Oauth2ServerErrorResponseError3({
680
+ error: Oauth2ErrorCodes3.InvalidRequest,
681
+ error_description: 'The "wallet_nonce" parameter MUST match the "expectedNonce" parameter when the "expectedNonce" parameter is provided.'
682
+ });
678
683
  }
679
- const schemePart = clientId.substring(0, colonIndex);
680
- const identifierPart = clientId.substring(colonIndex + 1);
681
- if (!parserConfigWithDefaults.supportedSchemes.includes(schemePart)) {
682
- throw new Oauth2ServerErrorResponseError5({
683
- error: Oauth2ErrorCodes4.InvalidRequest,
684
- error_description: `Unsupported client identifier scheme. ${schemePart} is not supported.`
684
+ if (params.client_id.startsWith("web-origin:")) {
685
+ throw new Oauth2ServerErrorResponseError3({
686
+ error: Oauth2ErrorCodes3.InvalidRequest,
687
+ 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}`
685
688
  });
686
689
  }
687
- const scheme = schemePart;
688
- if (scheme === "https") {
689
- if (!clientId.startsWith("https://") && !(getGlobalConfig().allowInsecureUrls && clientId.startsWith("http://"))) {
690
- throw new Oauth2ServerErrorResponseError5({
691
- error: Oauth2ErrorCodes4.InvalidRequest,
692
- error_description: "Invalid client identifier. Client identifier must start with https:// or http:// if allowInsecureUrls is true."
693
- });
694
- }
695
- return {
696
- scheme,
697
- identifier: clientId,
698
- originalValue: clientId,
699
- trustChain: authorizationRequestPayload.trust_chain
700
- };
690
+ };
691
+
692
+ // src/authorization-request/validate-authorization-request-dc-api.ts
693
+ import { Oauth2ErrorCodes as Oauth2ErrorCodes4, Oauth2ServerErrorResponseError as Oauth2ServerErrorResponseError4 } from "@openid4vc/oauth2";
694
+ var validateOpenid4vpAuthorizationRequestDcApiPayload = (options) => {
695
+ const { params, isJarRequest, disableOriginValidation, origin } = options;
696
+ if (isJarRequest && !params.expected_origins) {
697
+ throw new Oauth2ServerErrorResponseError4({
698
+ error: Oauth2ErrorCodes4.InvalidRequest,
699
+ error_description: `The 'expected_origins' parameter MUST be present when using the dc_api response mode in combinaction with jar.`
700
+ });
701
701
  }
702
- if (scheme === "redirect_uri") {
703
- if (jar) {
704
- throw new Oauth2ServerErrorResponseError5({
705
- error: Oauth2ErrorCodes4.InvalidRequest,
706
- error_description: 'Using client identifier scheme "redirect_uri" the request MUST NOT be signed.'
707
- });
708
- }
709
- if (isOpenid4vpAuthorizationRequestDcApi(authorizationRequestPayload)) {
710
- throw new Oauth2ServerErrorResponseError5({
711
- error: Oauth2ErrorCodes4.InvalidRequest,
712
- error_description: `The client identifier scheme 'redirect_uri' is not supported when using the dc_api response mode.`
713
- });
714
- }
715
- return {
716
- scheme,
717
- identifier: identifierPart,
718
- originalValue: clientId,
719
- redirectUri: authorizationRequestPayload.redirect_uri ?? authorizationRequestPayload.response_uri
720
- };
702
+ if ([params.presentation_definition, params.dcql_query].filter(Boolean).length !== 1) {
703
+ throw new Oauth2ServerErrorResponseError4({
704
+ error: Oauth2ErrorCodes4.InvalidRequest,
705
+ error_description: "Exactly one of the following parameters MUST be present in the Authorization Request: dcql_query or presentation_definition"
706
+ });
721
707
  }
722
- if (scheme === "did") {
723
- if (!jar) {
724
- throw new Oauth2ServerErrorResponseError5({
708
+ if (params.expected_origins && !disableOriginValidation) {
709
+ if (!origin) {
710
+ throw new Oauth2ServerErrorResponseError4({
725
711
  error: Oauth2ErrorCodes4.InvalidRequest,
726
- error_description: 'Using client identifier scheme "did" requires a signed JAR request.'
712
+ error_description: `Failed to validate the 'origin' of the authorization request. The 'origin' was not provided.`
727
713
  });
728
714
  }
729
- if (!clientId.startsWith("did:")) {
730
- throw new Oauth2ServerErrorResponseError5({
715
+ if (params.expected_origins && !params.expected_origins.includes(origin)) {
716
+ throw new Oauth2ServerErrorResponseError4({
731
717
  error: Oauth2ErrorCodes4.InvalidRequest,
732
- error_description: "Invalid client identifier. Client identifier must start with 'did:'"
718
+ error_description: `The 'expected_origins' parameter MUST include the origin of the authorization request. Current: ${params.expected_origins.join(", ")}`
733
719
  });
734
720
  }
735
- if (!jar.signer.publicJwk.kid) {
736
- throw new Oauth2ServerErrorResponseError5({
737
- error: Oauth2ErrorCodes4.InvalidRequest,
738
- error_description: `Missing required 'kid' for client identifier scheme: did`
739
- });
721
+ }
722
+ };
723
+
724
+ // src/authorization-request/create-authorization-request.ts
725
+ async function createOpenid4vpAuthorizationRequest(options) {
726
+ const { jar, scheme = "openid4vp://", wallet, callbacks } = options;
727
+ let additionalJwtPayload;
728
+ let authorizationRequestPayload;
729
+ if (isOpenid4vpAuthorizationRequestDcApi(options.authorizationRequestPayload)) {
730
+ authorizationRequestPayload = parseWithErrorHandling2(
731
+ zOpenid4vpAuthorizationRequestDcApi,
732
+ options.authorizationRequestPayload,
733
+ "Invalid authorization request. Could not parse openid4vp dc_api authorization request."
734
+ );
735
+ if (jar && !authorizationRequestPayload.expected_origins) {
736
+ throw new Oauth2Error4(
737
+ `The 'expected_origins' parameter MUST be present when using the dc_api response mode in combination with jar.`
738
+ );
740
739
  }
741
- if (!jar.signer.publicJwk.kid?.startsWith(clientId)) {
742
- throw new Oauth2ServerErrorResponseError5({
743
- error: Oauth2ErrorCodes4.InvalidRequest,
744
- error_description: 'With client identifier scheme "did" the JAR request must be signed by the same DID as the client identifier.'
745
- });
740
+ validateOpenid4vpAuthorizationRequestDcApiPayload({
741
+ params: authorizationRequestPayload,
742
+ isJarRequest: Boolean(jar),
743
+ disableOriginValidation: true
744
+ });
745
+ } else {
746
+ authorizationRequestPayload = parseWithErrorHandling2(
747
+ zOpenid4vpAuthorizationRequest,
748
+ options.authorizationRequestPayload,
749
+ "Invalid authorization request. Could not parse openid4vp authorization request."
750
+ );
751
+ validateOpenid4vpAuthorizationRequestPayload({
752
+ params: authorizationRequestPayload,
753
+ walletVerificationOptions: wallet
754
+ });
755
+ }
756
+ if (jar) {
757
+ if (!jar.additionalJwtPayload?.aud) {
758
+ additionalJwtPayload = { ...jar.additionalJwtPayload, aud: jar.requestUri };
746
759
  }
760
+ const jarResult = await createJarAuthorizationRequest({
761
+ ...jar,
762
+ authorizationRequestPayload,
763
+ additionalJwtPayload,
764
+ callbacks
765
+ });
766
+ const url2 = new URL3(scheme);
767
+ url2.search = `?${new URLSearchParams([
768
+ ...url2.searchParams.entries(),
769
+ ...objectToQueryParams(jarResult.jarAuthorizationRequest).entries()
770
+ ]).toString()}`;
747
771
  return {
748
- scheme,
749
- identifier: clientId,
750
- originalValue: clientId,
751
- didUrl: jar.signer.publicJwk.kid
772
+ authorizationRequestPayload,
773
+ authorizationRequestObject: jarResult.jarAuthorizationRequest,
774
+ authorizationRequest: url2.toString(),
775
+ jar: { ...jar, ...jarResult }
752
776
  };
753
777
  }
754
- if (scheme === "x509_san_dns" || scheme === "x509_san_uri") {
755
- if (!jar) {
756
- throw new Oauth2ServerErrorResponseError5({
757
- error: Oauth2ErrorCodes4.InvalidRequest,
758
- error_description: 'Using client identifier scheme "x509_san_dns" or "x509_san_uri" requires a signed JAR request.'
759
- });
760
- }
761
- if (jar.signer.method !== "x5c") {
762
- throw new Oauth2ServerErrorResponseError5({
763
- error: Oauth2ErrorCodes4.InvalidRequest,
764
- error_description: "Something went wrong. The JWT signer method is not x5c but the client identifier scheme is x509_san_dns."
765
- });
766
- }
767
- if (scheme === "x509_san_dns") {
768
- if (!options.callbacks.getX509CertificateMetadata) {
769
- throw new Oauth2ServerErrorResponseError5(
770
- {
771
- error: Oauth2ErrorCodes4.ServerError
772
- },
773
- {
774
- internalMessage: "Missing required 'getX509CertificateMetadata' callback for verification of 'x509_san_dns' client id scheme"
775
- }
776
- );
777
- }
778
- const { sanDnsNames } = options.callbacks.getX509CertificateMetadata(jar.signer.x5c[0]);
779
- if (!sanDnsNames.includes(identifierPart)) {
780
- throw new Oauth2ServerErrorResponseError5({
781
- error: Oauth2ErrorCodes4.InvalidRequest,
782
- error_description: `Invalid client identifier. One of the leaf certificates san dns names [${sanDnsNames.join(", ")}] must match the client identifier '${identifierPart}'. `
783
- });
784
- }
785
- if (!isOpenid4vpAuthorizationRequestDcApi(authorizationRequestPayload)) {
786
- const uri = authorizationRequestPayload.redirect_uri ?? authorizationRequestPayload.response_uri;
787
- if (!uri || new URL3(uri).hostname !== identifierPart) {
788
- throw new Oauth2ServerErrorResponseError5({
789
- error: Oauth2ErrorCodes4.InvalidRequest,
790
- 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."
791
- });
792
- }
793
- }
794
- } else if (scheme === "x509_san_uri") {
795
- if (!options.callbacks.getX509CertificateMetadata) {
796
- throw new Oauth2ServerErrorResponseError5(
797
- {
798
- error: Oauth2ErrorCodes4.ServerError
799
- },
800
- {
801
- internalMessage: "Missing required 'getX509CertificateMetadata' callback for verification of 'x509_san_uri' client id scheme"
802
- }
803
- );
804
- }
805
- const { sanUriNames } = options.callbacks.getX509CertificateMetadata(jar.signer.x5c[0]);
806
- if (!sanUriNames.includes(identifierPart)) {
807
- throw new Oauth2ServerErrorResponseError5({
808
- error: Oauth2ErrorCodes4.InvalidRequest,
809
- error_description: `Invalid client identifier. One of the leaf certificates san uri names [${sanUriNames.join(", ")}] must match the client identifier '${identifierPart}'.`
810
- });
811
- }
812
- if (!isOpenid4vpAuthorizationRequestDcApi(authorizationRequestPayload)) {
813
- const uri = authorizationRequestPayload.redirect_uri || authorizationRequestPayload.response_uri;
814
- if (!uri || uri !== identifierPart) {
815
- throw new Oauth2ServerErrorResponseError5({
816
- error: Oauth2ErrorCodes4.InvalidRequest,
817
- error_description: "The redirect_uri value MUST match the Client Identifier without the prefix x509_san_uri"
818
- });
819
- }
820
- }
778
+ const url = new URL3(scheme);
779
+ url.search = `?${new URLSearchParams([
780
+ ...url.searchParams.entries(),
781
+ ...objectToQueryParams(authorizationRequestPayload).entries()
782
+ ]).toString()}`;
783
+ return {
784
+ authorizationRequestPayload,
785
+ authorizationRequestObject: authorizationRequestPayload,
786
+ authorizationRequest: url.toString(),
787
+ jar: void 0
788
+ };
789
+ }
790
+
791
+ // src/authorization-request/parse-authorization-request-params.ts
792
+ import { decodeJwt as decodeJwt2 } from "@openid4vc/oauth2";
793
+ import { parseWithErrorHandling as parseWithErrorHandling3 } from "@openid4vc/utils";
794
+ import z10 from "zod";
795
+
796
+ // src/jar/z-jar-authorization-request.ts
797
+ import { Oauth2ServerErrorResponseError as Oauth2ServerErrorResponseError5 } from "@openid4vc/oauth2";
798
+ import { zHttpsUrl as zHttpsUrl4 } from "@openid4vc/utils";
799
+ import { z as z9 } from "zod";
800
+ var zJarAuthorizationRequest = z9.object({
801
+ request: z9.optional(z9.string()),
802
+ request_uri: z9.optional(zHttpsUrl4),
803
+ request_uri_method: z9.optional(z9.string()),
804
+ client_id: z9.optional(z9.string())
805
+ }).passthrough();
806
+ function validateJarRequestParams(options) {
807
+ const { jarRequestParams } = options;
808
+ if (jarRequestParams.request && jarRequestParams.request_uri) {
809
+ throw new Oauth2ServerErrorResponseError5({
810
+ error: "invalid_request_object",
811
+ error_description: "request and request_uri cannot both be present in a JAR request"
812
+ });
813
+ }
814
+ if (!jarRequestParams.request && !jarRequestParams.request_uri) {
815
+ throw new Oauth2ServerErrorResponseError5({
816
+ error: "invalid_request_object",
817
+ error_description: "request or request_uri must be present"
818
+ });
819
+ }
820
+ return jarRequestParams;
821
+ }
822
+ function isJarAuthorizationRequest(request) {
823
+ return "request" in request || "request_uri" in request;
824
+ }
825
+
826
+ // src/authorization-request/parse-authorization-request-params.ts
827
+ function parseOpenid4vpAuthorizationRequest(options) {
828
+ const { authorizationRequest } = options;
829
+ let provided = "params";
830
+ let params;
831
+ if (typeof authorizationRequest === "string") {
832
+ if (authorizationRequest.includes("://")) {
833
+ params = parseWithErrorHandling3(
834
+ zOpenid4vpAuthorizationRequestFromUriParams,
835
+ authorizationRequest,
836
+ "Unable to parse openid4vp authorization request uri to a valid object"
837
+ );
838
+ provided = "uri";
839
+ } else {
840
+ const decoded = decodeJwt2({ jwt: authorizationRequest });
841
+ params = decoded.payload;
842
+ provided = "jwt";
821
843
  }
844
+ } else {
845
+ params = authorizationRequest;
846
+ }
847
+ const parsedRequest = parseWithErrorHandling3(
848
+ z10.union([zOpenid4vpAuthorizationRequest, zJarAuthorizationRequest, zOpenid4vpAuthorizationRequestDcApi]),
849
+ params
850
+ );
851
+ if (isJarAuthorizationRequest(parsedRequest)) {
822
852
  return {
823
- scheme,
824
- identifier: identifierPart,
825
- originalValue: clientId,
826
- x5c: jar.signer.x5c
853
+ type: "jar",
854
+ provided,
855
+ params: parsedRequest
827
856
  };
828
857
  }
829
- if (scheme === "web-origin") {
858
+ if (isOpenid4vpAuthorizationRequestDcApi(parsedRequest)) {
830
859
  return {
831
- scheme,
832
- identifier: identifierPart,
833
- originalValue: clientId,
834
- clientMetadata: authorizationRequestPayload.client_metadata
860
+ type: "openid4vp_dc_api",
861
+ provided,
862
+ params: parsedRequest
835
863
  };
836
864
  }
837
- if (scheme === "verifier_attestation") {
838
- if (!jar) {
839
- throw new Oauth2ServerErrorResponseError5({
840
- error: Oauth2ErrorCodes4.InvalidRequest,
841
- error_description: 'Using client identifier scheme "verifier_attestation" requires a signed JAR request.'
842
- });
843
- }
844
- }
845
865
  return {
846
- scheme,
847
- identifier: identifierPart,
848
- originalValue: clientId
866
+ type: "openid4vp",
867
+ provided,
868
+ params: parsedRequest
849
869
  };
850
870
  }
851
871
 
872
+ // src/authorization-request/resolve-authorization-request.ts
873
+ import { Oauth2ErrorCodes as Oauth2ErrorCodes9, Oauth2ServerErrorResponseError as Oauth2ServerErrorResponseError10 } from "@openid4vc/oauth2";
874
+ import { parseWithErrorHandling as parseWithErrorHandling4 } from "@openid4vc/utils";
875
+ import z14 from "zod";
876
+
852
877
  // src/fetch-client-metadata.ts
853
878
  import { Oauth2ErrorCodes as Oauth2ErrorCodes5, Oauth2ServerErrorResponseError as Oauth2ServerErrorResponseError6 } from "@openid4vc/oauth2";
854
879
  import { ContentType, createZodFetcher } from "@openid4vc/utils";
@@ -1547,7 +1572,7 @@ async function parseJarmAuthorizationResponse(options) {
1547
1572
  // src/authorization-response/parse-authorization-response.ts
1548
1573
  async function parseOpenid4vpAuthorizationResponse(options) {
1549
1574
  const { authorizationResponse, callbacks, authorizationRequestPayload, origin } = options;
1550
- const expectedClientId = getClientId({ authorizationRequestPayload, origin });
1575
+ const expectedClientId = getOpenid4vpClientId({ authorizationRequestPayload, origin });
1551
1576
  if (authorizationResponse.response) {
1552
1577
  return parseJarmAuthorizationResponse({
1553
1578
  jarmResponseJwt: authorizationResponse.response,
@@ -1585,8 +1610,8 @@ var Openid4vpClient = class {
1585
1610
  constructor(options) {
1586
1611
  this.options = options;
1587
1612
  }
1588
- parseOpenid4vpAuthorizationRequestPayload(options) {
1589
- return parseOpenid4vpAuthorizationRequestPayload(options);
1613
+ parseOpenid4vpAuthorizationRequest(options) {
1614
+ return parseOpenid4vpAuthorizationRequest(options);
1590
1615
  }
1591
1616
  async resolveOpenId4vpAuthorizationRequest(options) {
1592
1617
  return resolveOpenid4vpAuthorizationRequest({ ...options, callbacks: this.options.callbacks });
@@ -1677,7 +1702,7 @@ var Openid4vpVerifier = class {
1677
1702
  return createOpenid4vpAuthorizationRequest({ ...options, callbacks: this.options.callbacks });
1678
1703
  }
1679
1704
  parseOpenid4vpAuthorizationRequestPayload(options) {
1680
- return parseOpenid4vpAuthorizationRequestPayload(options);
1705
+ return parseOpenid4vpAuthorizationRequest(options);
1681
1706
  }
1682
1707
  parseOpenid4vpAuthorizationResponse(options) {
1683
1708
  return parseOpenid4vpAuthorizationResponse(options);
@@ -1695,7 +1720,10 @@ var Openid4vpVerifier = class {
1695
1720
  return parseTransactionData(options);
1696
1721
  }
1697
1722
  verifyTransactionData(options) {
1698
- return verifyTransactionData(options);
1723
+ return verifyTransactionData({
1724
+ ...options,
1725
+ callbacks: this.options.callbacks
1726
+ });
1699
1727
  }
1700
1728
  };
1701
1729
 
@@ -1722,11 +1750,12 @@ export {
1722
1750
  Openid4vpVerifier,
1723
1751
  createOpenid4vpAuthorizationRequest,
1724
1752
  createOpenid4vpAuthorizationResponse,
1753
+ getOpenid4vpClientId,
1725
1754
  isJarmResponseMode,
1726
1755
  isOpenid4vpAuthorizationRequestDcApi,
1727
1756
  parseDcqlVpToken,
1728
1757
  parseJarmAuthorizationResponse,
1729
- parseOpenid4vpAuthorizationRequestPayload,
1758
+ parseOpenid4vpAuthorizationRequest,
1730
1759
  parseOpenid4vpAuthorizationResponse,
1731
1760
  parsePexVpToken,
1732
1761
  parseTransactionData,