@pagopa/io-react-native-wallet 2.0.0-next.3 → 2.0.0-next.5

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.
Files changed (131) hide show
  1. package/lib/commonjs/credential/issuance/04-complete-user-authorization.js +75 -57
  2. package/lib/commonjs/credential/issuance/04-complete-user-authorization.js.map +1 -1
  3. package/lib/commonjs/credential/issuance/06-obtain-credential.js.map +1 -1
  4. package/lib/commonjs/credential/issuance/07-verify-and-parse-credential.js +3 -3
  5. package/lib/commonjs/credential/issuance/07-verify-and-parse-credential.js.map +1 -1
  6. package/lib/commonjs/credential/issuance/README.md +45 -34
  7. package/lib/commonjs/credential/issuance/types.js +1 -0
  8. package/lib/commonjs/credential/issuance/types.js.map +1 -1
  9. package/lib/commonjs/credential/presentation/07-evaluate-dcql-query.js +6 -13
  10. package/lib/commonjs/credential/presentation/07-evaluate-dcql-query.js.map +1 -1
  11. package/lib/commonjs/credential/presentation/07-evaluate-input-descriptor.js +7 -8
  12. package/lib/commonjs/credential/presentation/07-evaluate-input-descriptor.js.map +1 -1
  13. package/lib/commonjs/credential/presentation/types.js +1 -1
  14. package/lib/commonjs/credential/presentation/types.js.map +1 -1
  15. package/lib/commonjs/credential/status/{02-status-attestation.js → 02-status-assertion.js} +28 -22
  16. package/lib/commonjs/credential/status/02-status-assertion.js.map +1 -0
  17. package/lib/commonjs/credential/status/03-verify-and-parse-status-assertion.js +85 -0
  18. package/lib/commonjs/credential/status/03-verify-and-parse-status-assertion.js.map +1 -0
  19. package/lib/commonjs/credential/status/README.md +22 -20
  20. package/lib/commonjs/credential/status/index.js +6 -6
  21. package/lib/commonjs/credential/status/index.js.map +1 -1
  22. package/lib/commonjs/credential/status/types.js +48 -15
  23. package/lib/commonjs/credential/status/types.js.map +1 -1
  24. package/lib/commonjs/sd-jwt/index.js +6 -1
  25. package/lib/commonjs/sd-jwt/index.js.map +1 -1
  26. package/lib/commonjs/sd-jwt/types.js +25 -9
  27. package/lib/commonjs/sd-jwt/types.js.map +1 -1
  28. package/lib/commonjs/utils/credentials.js +33 -0
  29. package/lib/commonjs/utils/credentials.js.map +1 -0
  30. package/lib/commonjs/utils/crypto.js +1 -7
  31. package/lib/commonjs/utils/crypto.js.map +1 -1
  32. package/lib/commonjs/utils/jwk.js +12 -0
  33. package/lib/commonjs/utils/jwk.js.map +1 -1
  34. package/lib/commonjs/wallet-instance-attestation/types.js +1 -2
  35. package/lib/commonjs/wallet-instance-attestation/types.js.map +1 -1
  36. package/lib/module/credential/issuance/04-complete-user-authorization.js +76 -58
  37. package/lib/module/credential/issuance/04-complete-user-authorization.js.map +1 -1
  38. package/lib/module/credential/issuance/06-obtain-credential.js.map +1 -1
  39. package/lib/module/credential/issuance/07-verify-and-parse-credential.js +4 -4
  40. package/lib/module/credential/issuance/07-verify-and-parse-credential.js.map +1 -1
  41. package/lib/module/credential/issuance/README.md +45 -34
  42. package/lib/module/credential/issuance/types.js +1 -0
  43. package/lib/module/credential/issuance/types.js.map +1 -1
  44. package/lib/module/credential/presentation/07-evaluate-dcql-query.js +6 -13
  45. package/lib/module/credential/presentation/07-evaluate-dcql-query.js.map +1 -1
  46. package/lib/module/credential/presentation/07-evaluate-input-descriptor.js +7 -8
  47. package/lib/module/credential/presentation/07-evaluate-input-descriptor.js.map +1 -1
  48. package/lib/module/credential/presentation/types.js +1 -1
  49. package/lib/module/credential/presentation/types.js.map +1 -1
  50. package/lib/module/credential/status/{02-status-attestation.js → 02-status-assertion.js} +28 -22
  51. package/lib/module/credential/status/02-status-assertion.js.map +1 -0
  52. package/lib/module/credential/status/03-verify-and-parse-status-assertion.js +78 -0
  53. package/lib/module/credential/status/03-verify-and-parse-status-assertion.js.map +1 -0
  54. package/lib/module/credential/status/README.md +22 -20
  55. package/lib/module/credential/status/index.js +3 -3
  56. package/lib/module/credential/status/index.js.map +1 -1
  57. package/lib/module/credential/status/types.js +43 -12
  58. package/lib/module/credential/status/types.js.map +1 -1
  59. package/lib/module/sd-jwt/index.js +6 -1
  60. package/lib/module/sd-jwt/index.js.map +1 -1
  61. package/lib/module/sd-jwt/types.js +25 -9
  62. package/lib/module/sd-jwt/types.js.map +1 -1
  63. package/lib/module/utils/credentials.js +26 -0
  64. package/lib/module/utils/credentials.js.map +1 -0
  65. package/lib/module/utils/crypto.js +2 -8
  66. package/lib/module/utils/crypto.js.map +1 -1
  67. package/lib/module/utils/jwk.js +11 -1
  68. package/lib/module/utils/jwk.js.map +1 -1
  69. package/lib/module/wallet-instance-attestation/types.js +1 -2
  70. package/lib/module/wallet-instance-attestation/types.js.map +1 -1
  71. package/lib/typescript/credential/issuance/04-complete-user-authorization.d.ts +7 -14
  72. package/lib/typescript/credential/issuance/04-complete-user-authorization.d.ts.map +1 -1
  73. package/lib/typescript/credential/issuance/06-obtain-credential.d.ts.map +1 -1
  74. package/lib/typescript/credential/issuance/07-verify-and-parse-credential.d.ts.map +1 -1
  75. package/lib/typescript/credential/issuance/types.d.ts +3 -0
  76. package/lib/typescript/credential/issuance/types.d.ts.map +1 -1
  77. package/lib/typescript/credential/presentation/01-start-flow.d.ts +2 -2
  78. package/lib/typescript/credential/presentation/07-evaluate-dcql-query.d.ts +4 -3
  79. package/lib/typescript/credential/presentation/07-evaluate-dcql-query.d.ts.map +1 -1
  80. package/lib/typescript/credential/presentation/07-evaluate-input-descriptor.d.ts +9 -5
  81. package/lib/typescript/credential/presentation/07-evaluate-input-descriptor.d.ts.map +1 -1
  82. package/lib/typescript/credential/presentation/types.d.ts +3 -4
  83. package/lib/typescript/credential/presentation/types.d.ts.map +1 -1
  84. package/lib/typescript/credential/status/02-status-assertion.d.ts +23 -0
  85. package/lib/typescript/credential/status/02-status-assertion.d.ts.map +1 -0
  86. package/lib/typescript/credential/status/03-verify-and-parse-status-assertion.d.ts +21 -0
  87. package/lib/typescript/credential/status/03-verify-and-parse-status-assertion.d.ts.map +1 -0
  88. package/lib/typescript/credential/status/index.d.ts +4 -4
  89. package/lib/typescript/credential/status/index.d.ts.map +1 -1
  90. package/lib/typescript/credential/status/types.d.ts +499 -22
  91. package/lib/typescript/credential/status/types.d.ts.map +1 -1
  92. package/lib/typescript/sd-jwt/index.d.ts +68 -40
  93. package/lib/typescript/sd-jwt/index.d.ts.map +1 -1
  94. package/lib/typescript/sd-jwt/types.d.ts +97 -46
  95. package/lib/typescript/sd-jwt/types.d.ts.map +1 -1
  96. package/lib/typescript/utils/credentials.d.ts +11 -0
  97. package/lib/typescript/utils/credentials.d.ts.map +1 -0
  98. package/lib/typescript/utils/crypto.d.ts.map +1 -1
  99. package/lib/typescript/utils/jwk.d.ts +7 -0
  100. package/lib/typescript/utils/jwk.d.ts.map +1 -1
  101. package/package.json +1 -1
  102. package/src/credential/issuance/04-complete-user-authorization.ts +79 -85
  103. package/src/credential/issuance/06-obtain-credential.ts +4 -1
  104. package/src/credential/issuance/07-verify-and-parse-credential.ts +4 -6
  105. package/src/credential/issuance/README.md +45 -34
  106. package/src/credential/issuance/types.ts +1 -0
  107. package/src/credential/presentation/07-evaluate-dcql-query.ts +16 -17
  108. package/src/credential/presentation/07-evaluate-input-descriptor.ts +16 -13
  109. package/src/credential/presentation/types.ts +1 -2
  110. package/src/credential/status/{02-status-attestation.ts → 02-status-assertion.ts} +37 -28
  111. package/src/credential/status/03-verify-and-parse-status-assertion.ts +109 -0
  112. package/src/credential/status/README.md +22 -20
  113. package/src/credential/status/index.ts +7 -14
  114. package/src/credential/status/types.ts +62 -15
  115. package/src/sd-jwt/index.ts +5 -1
  116. package/src/sd-jwt/types.ts +24 -10
  117. package/src/utils/credentials.ts +29 -0
  118. package/src/utils/crypto.ts +12 -20
  119. package/src/utils/jwk.ts +15 -1
  120. package/src/wallet-instance-attestation/types.ts +1 -1
  121. package/lib/commonjs/credential/status/02-status-attestation.js.map +0 -1
  122. package/lib/commonjs/credential/status/03-verify-and-parse-status-attestation.js +0 -55
  123. package/lib/commonjs/credential/status/03-verify-and-parse-status-attestation.js.map +0 -1
  124. package/lib/module/credential/status/02-status-attestation.js.map +0 -1
  125. package/lib/module/credential/status/03-verify-and-parse-status-attestation.js +0 -49
  126. package/lib/module/credential/status/03-verify-and-parse-status-attestation.js.map +0 -1
  127. package/lib/typescript/credential/status/02-status-attestation.d.ts +0 -19
  128. package/lib/typescript/credential/status/02-status-attestation.d.ts.map +0 -1
  129. package/lib/typescript/credential/status/03-verify-and-parse-status-attestation.d.ts +0 -24
  130. package/lib/typescript/credential/status/03-verify-and-parse-status-attestation.d.ts.map +0 -1
  131. package/src/credential/status/03-verify-and-parse-status-attestation.ts +0 -70
@@ -10,16 +10,16 @@ import { IssuerResponseError, ValidationFailed } from "../../utils/errors";
10
10
  import type { EvaluateIssuerTrust } from "./02-evaluate-issuer-trust";
11
11
  import {
12
12
  decode,
13
- encodeBase64,
14
13
  SignJWT,
15
14
  type CryptoContext,
16
15
  } from "@pagopa/io-react-native-jwt";
17
- import { RequestObject } from "../presentation/types";
18
- import { v4 as uuidv4 } from "uuid";
16
+ import { type RemotePresentation, RequestObject } from "../presentation/types";
19
17
  import { ResponseUriResultShape } from "./types";
20
18
  import { getJwtFromFormPost } from "../../utils/decoder";
21
19
  import { AuthorizationError, AuthorizationIdpError } from "./errors";
22
20
  import { LogLevel, Logger } from "../../utils/logging";
21
+ import { Presentation } from "..";
22
+ import type { DcqlQuery } from "dcql";
23
23
 
24
24
  /**
25
25
  * The interface of the phase to complete User authorization via strong identification when the response mode is "query" and the request credential is a PersonIdentificationData.
@@ -30,11 +30,10 @@ export type CompleteUserAuthorizationWithQueryMode = (
30
30
 
31
31
  export type CompleteUserAuthorizationWithFormPostJwtMode = (
32
32
  requestObject: Out<GetRequestedCredentialToBePresented>,
33
+ pid: string,
33
34
  context: {
34
35
  wiaCryptoContext: CryptoContext;
35
36
  pidCryptoContext: CryptoContext;
36
- pid: string;
37
- walletInstanceAttestation: string;
38
37
  appFetch?: GlobalFetch["fetch"];
39
38
  }
40
39
  ) => Promise<AuthorizationResult>;
@@ -158,103 +157,54 @@ export const getRequestedCredentialToBePresented: GetRequestedCredentialToBePres
158
157
  };
159
158
 
160
159
  /**
161
- * WARNING: This function must be called after {@link startUserAuthorization}. The next function to be called is {@link completeUserAuthorizationWithFormPostJwtMode}.
160
+ * WARNING: This function must be called after {@link getRequestedCredentialToBePresented}. The next function to be called is {@link authorizeAccess}.
162
161
  * The interface of the phase to complete User authorization via presentation of existing credentials when the response mode is "form_post.jwt".
163
- * It is used as a first step to complete the user authorization by obtaining the requested credential to be presented from the authorization server.
164
- * The information is obtained by performing a GET request to the authorization endpoint with request_uri and client_id parameters.
165
- * @param issuerRequestUri the URI of the issuer where the request is sent
166
- * @param clientId Identifies the current client across all the requests of the issuing flow returned by {@link startUserAuthorization}
167
- * @param issuerConf The issuer configuration returned by {@link evaluateIssuerTrust}
168
- * @param context.walletInstanceAccestation the Wallet Instance's attestation to be presented
169
- * @param context.pid the PID to be presented
170
- * @param context.wiaCryptoContext The Wallet Instance's crypto context associated with the walletInstanceAttestation parameter
171
- * @param context.pidCryptoContext The PID crypto context associated with the pid parameter
172
- * @param context.appFetch (optional) fetch api implementation. Default: built-in fetch
162
+ * The information is obtained by performing a POST request to the endpoint received in the response_uri field of the requestObject, where the Authorization Response payload is posted.
163
+ * Following this,the redirect_uri from the response is used to obtain the final authorization response.
164
+ * @param requestObject - The request object containing the necessary parameters for authorization.
165
+ * @param pid The `PID` that must be presented for the issuance of credentials.
166
+ * @param appFetch (optional) fetch api implementation. Default: built-in fetch
173
167
  * @throws {ValidationFailed} if an error while validating the response
174
168
  * @returns the authorization response which contains code, state and iss
175
169
  */
176
170
  export const completeUserAuthorizationWithFormPostJwtMode: CompleteUserAuthorizationWithFormPostJwtMode =
177
- async (requestObject, ctx) => {
171
+ async (
172
+ requestObject,
173
+ pid,
174
+ { wiaCryptoContext, pidCryptoContext, appFetch = fetch }
175
+ ) => {
178
176
  Logger.log(
179
177
  LogLevel.DEBUG,
180
178
  `The requeste credential is not a PersonIdentificationData, completing the user authorization with form_post.jwt mode`
181
179
  );
182
180
 
183
- const {
184
- wiaCryptoContext,
185
- pidCryptoContext,
186
- pid,
187
- walletInstanceAttestation,
188
- appFetch = fetch,
189
- } = ctx;
181
+ if (!requestObject.dcql_query) {
182
+ throw new Error("Invalid request object");
183
+ }
190
184
 
191
- const wiaWpToken = await new SignJWT(wiaCryptoContext)
192
- .setProtectedHeader({
193
- alg: "ES256",
194
- typ: "JWT",
195
- })
196
- .setPayload({
197
- vp: walletInstanceAttestation,
198
- jti: uuidv4().toString(),
199
- nonce: requestObject.nonce,
200
- })
201
- .setIssuedAt()
202
- .setExpirationTime("5m")
203
- .setAudience(requestObject.response_uri)
204
- .sign();
185
+ const dcqlQueryResult = Presentation.evaluateDcqlQuery(
186
+ [[pidCryptoContext, pid]],
187
+ requestObject.dcql_query as DcqlQuery
188
+ );
205
189
 
206
- const pidWpToken = await new SignJWT(pidCryptoContext)
207
- .setProtectedHeader({
208
- alg: "ES256",
209
- typ: "JWT",
190
+ const credentialsToPresent = dcqlQueryResult.map(
191
+ ({ requiredDisclosures, ...rest }) => ({
192
+ ...rest,
193
+ requestedClaims: requiredDisclosures.map(([, claimName]) => claimName),
210
194
  })
211
- .setPayload({
212
- vp: pid,
213
- jti: uuidv4().toString(),
214
- nonce: requestObject.nonce,
215
- })
216
- .setIssuedAt()
217
- .setExpirationTime("5m")
218
- .setAudience(requestObject.response_uri)
219
- .sign();
220
-
221
- Logger.log(
222
- LogLevel.DEBUG,
223
- `Wallet instance attestation JWT token: ${wiaWpToken}`
224
195
  );
225
196
 
226
- /* The path parameter refers to the vp_token variable of the authzResponsePayload and must point to the plain credential which
227
- * is cointaned in the `vp` property of the signed jwt token payload
228
- */
229
- const presentationSubmission = {
230
- definition_id: `${uuidv4()}`,
231
- id: `${uuidv4()}`,
232
- descriptor_map: [
233
- {
234
- id: "PersonIdentificationData",
235
- path: "$.vp_token[0].vp",
236
- format: "vc+sd-jwt",
237
- },
238
- {
239
- id: "WalletAttestation",
240
- path: "$.vp_token[1].vp",
241
- format: "jwt",
242
- },
243
- ],
244
- };
245
-
246
- Logger.log(
247
- LogLevel.DEBUG,
248
- `Presentation submission: ${JSON.stringify(presentationSubmission)}`
197
+ const remotePresentations = await Presentation.prepareRemotePresentations(
198
+ credentialsToPresent,
199
+ requestObject.nonce,
200
+ requestObject.client_id
249
201
  );
250
202
 
251
- const authzResponsePayload = encodeBase64(
252
- JSON.stringify({
253
- state: requestObject.state,
254
- presentation_submission: presentationSubmission,
255
- vp_token: [pidWpToken, wiaWpToken],
256
- })
257
- );
203
+ const authzResponsePayload = await createAuthzResponsePayload({
204
+ state: requestObject.state,
205
+ remotePresentations,
206
+ wiaCryptoContext,
207
+ });
258
208
 
259
209
  Logger.log(
260
210
  LogLevel.DEBUG,
@@ -334,3 +284,47 @@ export const parseAuthorizationResponse = (
334
284
  }
335
285
  return authResParsed.data;
336
286
  };
287
+
288
+ /**
289
+ * Creates the authorization response payload to be sent.
290
+ * This payload includes the state and the VP tokens for the presented credentials.
291
+ * The payload is encoded in Base64.
292
+ * @param state - The state parameter from the request object (optional).
293
+ * @param remotePresentations - An array of remote presentations containing credential IDs and their corresponding VP tokens.
294
+ * @returns The Base64 encoded authorization response payload.
295
+ */
296
+ const createAuthzResponsePayload = async ({
297
+ state,
298
+ remotePresentations,
299
+ wiaCryptoContext,
300
+ }: {
301
+ state?: string;
302
+ remotePresentations: RemotePresentation[];
303
+ wiaCryptoContext: CryptoContext;
304
+ }): Promise<string> => {
305
+ const { kid } = await wiaCryptoContext.getPublicKey();
306
+
307
+ return new SignJWT(wiaCryptoContext)
308
+ .setProtectedHeader({
309
+ typ: "jwt",
310
+ kid,
311
+ })
312
+ .setPayload({
313
+ /**
314
+ * TODO [SIW-2264]: `state` coming from `requestObject` is marked as `optional`
315
+ * At the moment, it is not entirely clear whether this value can indeed be omitted
316
+ * and, if so, what the consequences of its absence might be.
317
+ */
318
+ ...(state ? { state } : {}),
319
+ vp_token: remotePresentations.reduce(
320
+ (vp_token, { credentialId, vpToken }) => ({
321
+ ...vp_token,
322
+ [credentialId]: vpToken,
323
+ }),
324
+ {}
325
+ ),
326
+ })
327
+ .setIssuedAt()
328
+ .setExpirationTime("1h")
329
+ .sign();
330
+ };
@@ -33,7 +33,10 @@ export type ObtainCredential = (
33
33
  appFetch?: GlobalFetch["fetch"];
34
34
  },
35
35
  operationType?: "reissuing"
36
- ) => Promise<{ credential: string; format: string }>;
36
+ ) => Promise<{
37
+ credential: string;
38
+ format: string;
39
+ }>;
37
40
 
38
41
  export const createNonceProof = async (
39
42
  nonce: string,
@@ -2,12 +2,11 @@ import type { CryptoContext } from "@pagopa/io-react-native-jwt";
2
2
  import type { Out } from "../../utils/misc";
3
3
  import type { EvaluateIssuerTrust } from "./02-evaluate-issuer-trust";
4
4
  import { IoWalletError } from "../../utils/errors";
5
- import { SdJwt4VC } from "../../sd-jwt/types";
6
- import { verify as verifySdJwt } from "../../sd-jwt";
5
+ import { SdJwt4VC, verify as verifySdJwt } from "../../sd-jwt";
7
6
  import { getValueFromDisclosures } from "../../sd-jwt/converters";
8
- import type { JWK } from "../../utils/jwk";
7
+ import { isSameThumbprint, type JWK } from "../../utils/jwk";
9
8
  import type { ObtainCredential } from "./06-obtain-credential";
10
- import { LogLevel, Logger } from "../../utils/logging";
9
+ import { Logger, LogLevel } from "../../utils/logging";
11
10
 
12
11
  type IssuerConf = Out<EvaluateIssuerTrust>["issuerConf"];
13
12
  type CredentialConf =
@@ -169,8 +168,7 @@ async function verifyCredentialSdJwt(
169
168
  ]);
170
169
 
171
170
  const { cnf } = decodedCredential.sdJwt.payload;
172
-
173
- if (!cnf.jwk.kid || cnf.jwk.kid !== holderBindingKey.kid) {
171
+ if (!(await isSameThumbprint(cnf.jwk, holderBindingKey as JWK))) {
174
172
  const message = `Failed to verify holder binding, expected kid: ${holderBindingKey.kid}, got: ${decodedCredential.sdJwt.payload.cnf.jwk.kid}`;
175
173
  Logger.log(LogLevel.ERROR, message);
176
174
  throw new IoWalletError(message);
@@ -72,8 +72,6 @@ The expected result from the authentication process is in `form_post.jwt` format
72
72
  <summary>Credential issuance flow</summary>
73
73
 
74
74
  ```ts
75
- // TODO: [SIW-2209] update documentation in PR #219
76
-
77
75
  // Retrieve the integrity key tag from the store and create its context
78
76
  const integrityKeyTag = "example"; // Let's assume this is the key tag used to create the wallet instance
79
77
  const integrityContext = getIntegrityContext(integrityKeyTag);
@@ -98,17 +96,13 @@ const walletInstanceAttestation =
98
96
  appFetch,
99
97
  });
100
98
 
101
- const credentialType = "someCredential"; // Let's assume this is the credential type
102
-
103
- const eid = {
99
+ const pid = {
104
100
  credential: "example",
105
101
  parsedCredential: "example"
106
102
  keyTag: "example";
107
- credentialType: "eid";
103
+ credentialType: "PersonIdentificationData";
108
104
  };
109
105
 
110
- const eidCryptoContext = createCryptoContextFor(eid.keyTag);
111
-
112
106
  // Create credential crypto context
113
107
  const credentialKeyTag = uuidv4().toString();
114
108
  await generate(credentialKeyTag); // Let's assume this function generates a new hardware-backed key pair
@@ -117,22 +111,26 @@ const credentialCryptoContext = createCryptoContextFor(credentialKeyTag);
117
111
  // Start the issuance flow
118
112
  const startFlow: Credential.Issuance.StartFlow = () => ({
119
113
  issuerUrl: WALLET_EAA_PROVIDER_BASE_URL,
120
- credentialType,
114
+ credentialId: "someCredentialId",
121
115
  });
122
116
 
123
- const { issuerUrl } = startFlow();
117
+ const { issuerUrl, credentialId } = startFlow();
124
118
 
125
119
  // Evaluate issuer trust
126
120
  const { issuerConf } = await Credential.Issuance.evaluateIssuerTrust(issuerUrl);
127
121
 
128
122
  // Start user authorization
129
- const { issuerRequestUri, clientId, codeVerifier, credentialDefinition } =
130
- await Credential.Issuance.startUserAuthorization(issuerConf, credentialType, {
131
- walletInstanceAttestation,
132
- redirectUri,
133
- wiaCryptoContext,
134
- appFetch,
135
- });
123
+ const { issuerRequestUri, clientId, codeVerifier } =
124
+ await Credential.Issuance.startUserAuthorization(
125
+ issuerConf,
126
+ [credentialId],
127
+ {
128
+ walletInstanceAttestation,
129
+ redirectUri: REDIRECT_URI,
130
+ wiaCryptoContext,
131
+ appFetch,
132
+ }
133
+ );
136
134
 
137
135
  const requestObject =
138
136
  await Credential.Issuance.getRequestedCredentialToBePresented(
@@ -142,13 +140,12 @@ const requestObject =
142
140
  appFetch
143
141
  );
144
142
 
145
- // The app here should ask the user to confirm the required data contained in the requestObject
146
-
147
143
  // Complete the user authorization via form_post.jwt mode
148
144
  const { code } =
149
145
  await Credential.Issuance.completeUserAuthorizationWithFormPostJwtMode(
150
146
  requestObject,
151
- { wiaCryptoContext, pidCryptoContext, pid, walletInstanceAttestation }
147
+ pid.credential,
148
+ { wiaCryptoContext, pidCryptoContext: createCryptoContextFor(pid.keyTag) }
152
149
  );
153
150
 
154
151
  // Generate the DPoP context which will be used for the whole issuance flow
@@ -159,7 +156,7 @@ const { accessToken } = await Credential.Issuance.authorizeAccess(
159
156
  issuerConf,
160
157
  code,
161
158
  clientId,
162
- redirectUri,
159
+ redirectUri: REDIRECT_URI,
163
160
  codeVerifier,
164
161
  {
165
162
  walletInstanceAttestation,
@@ -169,12 +166,19 @@ const { accessToken } = await Credential.Issuance.authorizeAccess(
169
166
  }
170
167
  );
171
168
 
172
- // Obtain the credential
173
- const { credential, format } = await Credential.Issuance.obtainCredential(
169
+ // For simplicity, in this example flow we work on a single credential.
170
+ const { credential_configuration_id, credential_identifiers } =
171
+ accessToken.authorization_details[0]!;
172
+
173
+ // Obtain the credential
174
+ const { credential } = await Credential.Issuance.obtainCredential(
174
175
  issuerConf,
175
176
  accessToken,
176
177
  clientId,
177
- credentialDefinition,
178
+ {
179
+ credential_configuration_id,
180
+ credential_identifier: credential_identifiers[0],
181
+ },
178
182
  {
179
183
  credentialCryptoContext,
180
184
  dPopCryptoContext,
@@ -186,22 +190,29 @@ const { credential, format } = await Credential.Issuance.obtainCredential(
186
190
  * Parse and verify the credential. The ignoreMissingAttributes flag must be set to false or omitted in production.
187
191
  * WARNING: includeUndefinedAttributes should not be set to true in production in order to get only claims explicitly declared by the issuer.
188
192
  */
189
- const { parsedCredential } = await Credential.Issuance.verifyAndParseCredential(
190
- issuerConf,
191
- credential,
192
- format,
193
- {
194
- credentialCryptoContext,
195
- ignoreMissingAttributes: true,
196
- includeUndefinedAttributes: false
197
- }
198
- );
193
+ const { parsedCredential } =
194
+ await Credential.Issuance.verifyAndParseCredential(
195
+ issuerConf,
196
+ credential,
197
+ credential_configuration_id,
198
+ {
199
+ credentialCryptoContext,
200
+ ignoreMissingAttributes: true,
201
+ includeUndefinedAttributes: false
202
+ }
203
+ );
204
+
205
+ const credentialType =
206
+ issuerConf.openid_credential_issuer.credential_configurations_supported[
207
+ credential_configuration_id
208
+ ].scope;
199
209
 
200
210
  return {
201
211
  parsedCredential,
202
212
  credential,
203
213
  keyTag: credentialKeyTag,
204
214
  credentialType,
215
+ credentialConfigurationId: credential_configuration_id,
205
216
  };
206
217
  ```
207
218
 
@@ -11,6 +11,7 @@ export type TokenResponse = z.infer<typeof TokenResponse>;
11
11
 
12
12
  export const TokenResponse = z.object({
13
13
  access_token: z.string(),
14
+ refresh_token: z.string().optional(),
14
15
  authorization_details: z.array(AuthorizationDetail),
15
16
  expires_in: z.number(),
16
17
  token_type: z.string(),
@@ -2,9 +2,9 @@ import { DcqlQuery, DcqlError, DcqlQueryResult } from "dcql";
2
2
  import { isValiError } from "valibot";
3
3
  import { decode, prepareVpToken } from "../../sd-jwt";
4
4
  import type { Disclosure } from "../../sd-jwt/types";
5
- import { createCryptoContextFor } from "../../utils/crypto";
6
5
  import type { RemotePresentation } from "./types";
7
6
  import { CredentialsNotFoundError, type NotFoundDetail } from "./errors";
7
+ import type { CryptoContext } from "@pagopa/io-react-native-jwt";
8
8
 
9
9
  /**
10
10
  * The purpose for the credential request by the RP.
@@ -15,13 +15,13 @@ type CredentialPurpose = {
15
15
  };
16
16
 
17
17
  export type EvaluateDcqlQuery = (
18
- credentialsSdJwt: [string /* keyTag */, string /* credential */][],
18
+ credentialsSdJwt: [CryptoContext, string /* credential */][],
19
19
  query: DcqlQuery.Input
20
20
  ) => {
21
21
  id: string;
22
22
  vct: string;
23
23
  credential: string;
24
- keyTag: string;
24
+ cryptoContext: CryptoContext;
25
25
  requiredDisclosures: Disclosure[];
26
26
  purposes: CredentialPurpose[];
27
27
  }[];
@@ -30,7 +30,7 @@ export type PrepareRemotePresentations = (
30
30
  credentials: {
31
31
  id: string;
32
32
  credential: string;
33
- keyTag: string;
33
+ cryptoContext: CryptoContext;
34
34
  requestedClaims: string[];
35
35
  }[],
36
36
  nonce: string,
@@ -55,11 +55,6 @@ const mapCredentialToObject = (jwt: string) => {
55
55
  const { sdJwt, disclosures } = decode(jwt);
56
56
  const credentialFormat = sdJwt.header.typ;
57
57
 
58
- // TODO [SIW-2082]: support MDOC credentials
59
- if (credentialFormat !== "dc+sd-jwt") {
60
- throw new Error(`Unsupported credential format: ${credentialFormat}`);
61
- }
62
-
63
58
  return {
64
59
  vct: sdJwt.payload.vct,
65
60
  credential_format: credentialFormat,
@@ -100,7 +95,10 @@ const extractMissingCredentials = (
100
95
  ): NotFoundDetail[] => {
101
96
  return getDcqlQueryFailedMatches(queryResult).map(([id]) => {
102
97
  const credential = originalQuery.credentials.find((c) => c.id === id);
103
- if (credential?.format !== "dc+sd-jwt") {
98
+ if (
99
+ credential?.format !== "dc+sd-jwt" &&
100
+ credential?.format !== "vc+sd-jwt"
101
+ ) {
104
102
  throw new Error("Unsupported format"); // TODO [SIW-2082]: support MDOC credentials
105
103
  }
106
104
  return { id, vctValues: credential.meta?.vct_values };
@@ -114,7 +112,6 @@ export const evaluateDcqlQuery: EvaluateDcqlQuery = (
114
112
  const credentials = credentialsSdJwt.map(([, credential]) =>
115
113
  mapCredentialToObject(credential)
116
114
  );
117
-
118
115
  try {
119
116
  // Validate the query
120
117
  const parsedQuery = DcqlQuery.parse(query);
@@ -131,11 +128,14 @@ export const evaluateDcqlQuery: EvaluateDcqlQuery = (
131
128
  // Build an object vct:credentialJwt to map matched credentials to their JWT
132
129
  const credentialsSdJwtByVct = credentials.reduce(
133
130
  (acc, c, i) => ({ ...acc, [c.vct]: credentialsSdJwt[i]! }),
134
- {} as Record<string, [string /* keyTag */, string /* credential */]>
131
+ {} as Record<string, [CryptoContext, string /* credential */]>
135
132
  );
136
133
 
137
134
  return getDcqlQueryMatches(queryResult).map(([id, match]) => {
138
- if (match.output.credential_format !== "dc+sd-jwt") {
135
+ if (
136
+ match.output.credential_format !== "dc+sd-jwt" &&
137
+ match.output.credential_format !== "vc+sd-jwt"
138
+ ) {
139
139
  throw new Error("Unsupported format"); // TODO [SIW-2082]: support MDOC credentials
140
140
  }
141
141
  const { vct, claims } = match.output;
@@ -147,12 +147,12 @@ export const evaluateDcqlQuery: EvaluateDcqlQuery = (
147
147
  required: Boolean(credentialSet.required),
148
148
  }));
149
149
 
150
- const [keyTag, credential] = credentialsSdJwtByVct[vct]!;
150
+ const [cryptoContext, credential] = credentialsSdJwtByVct[vct]!;
151
151
  const requiredDisclosures = Object.values(claims) as Disclosure[];
152
152
  return {
153
153
  id,
154
154
  vct,
155
- keyTag,
155
+ cryptoContext,
156
156
  credential,
157
157
  requiredDisclosures,
158
158
  // When it is a match but no credential_sets are found, the credential is required by default
@@ -185,14 +185,13 @@ export const prepareRemotePresentations: PrepareRemotePresentations = async (
185
185
  const { vp_token } = await prepareVpToken(nonce, clientId, [
186
186
  item.credential,
187
187
  item.requestedClaims,
188
- createCryptoContextFor(item.keyTag),
188
+ item.cryptoContext,
189
189
  ]);
190
190
 
191
191
  return {
192
192
  credentialId: item.id,
193
193
  requestedClaims: item.requestedClaims,
194
194
  vpToken: vp_token,
195
- format: "dc+sd-jwt",
196
195
  };
197
196
  })
198
197
  );
@@ -1,10 +1,10 @@
1
1
  import { InputDescriptor, type LegacyRemotePresentation } from "./types";
2
2
  import { SdJwt4VC, type DisclosureWithEncoded } from "../../sd-jwt/types";
3
3
  import { decode, prepareVpToken } from "../../sd-jwt";
4
- import { createCryptoContextFor } from "../../utils/crypto";
5
4
  import { JSONPath } from "jsonpath-plus";
6
5
  import { CredentialsNotFoundError, MissingDataError } from "./errors";
7
6
  import Ajv from "ajv";
7
+ import type { CryptoContext } from "@pagopa/io-react-native-jwt";
8
8
 
9
9
  const ajv = new Ajv({ allErrors: true });
10
10
  const INDEX_CLAIM_NAME = 1;
@@ -23,13 +23,16 @@ export type EvaluateInputDescriptorSdJwt4VC = (
23
23
 
24
24
  export type EvaluateInputDescriptors = (
25
25
  descriptors: InputDescriptor[],
26
- credentialsSdJwt: [string /* keyTag */, string /* credential */][]
26
+ credentialsSdJwt: [
27
+ CryptoContext /* cryptoContext */,
28
+ string /* credential */,
29
+ ][]
27
30
  ) => Promise<
28
31
  {
29
32
  evaluatedDisclosure: EvaluatedDisclosures;
30
33
  inputDescriptor: InputDescriptor;
31
34
  credential: string;
32
- keyTag: string;
35
+ cryptoContext: CryptoContext;
33
36
  }[]
34
37
  >;
35
38
 
@@ -41,7 +44,7 @@ export type PrepareLegacyRemotePresentations = (
41
44
  requestedClaims: string[];
42
45
  inputDescriptor: InputDescriptor;
43
46
  credential: string;
44
- keyTag: string;
47
+ cryptoContext: CryptoContext;
45
48
  }[],
46
49
  nonce: string,
47
50
  client_id: string
@@ -247,7 +250,7 @@ export const evaluateInputDescriptorForSdJwt4VC: EvaluateInputDescriptorSdJwt4VC
247
250
  };
248
251
 
249
252
  type DecodedCredentialSdJwt = {
250
- keyTag: string;
253
+ cryptoContext: CryptoContext;
251
254
  credential: string;
252
255
  sdJwt: SdJwt4VC;
253
256
  disclosures: DisclosureWithEncoded[];
@@ -264,11 +267,11 @@ export const findCredentialSdJwt = (
264
267
  decodedSdJwtCredentials: DecodedCredentialSdJwt[]
265
268
  ): {
266
269
  matchedEvaluation: EvaluatedDisclosures;
267
- matchedKeyTag: string;
268
270
  matchedCredential: string;
271
+ cryptoContext: CryptoContext;
269
272
  } => {
270
273
  for (const {
271
- keyTag,
274
+ cryptoContext,
272
275
  credential,
273
276
  sdJwt,
274
277
  disclosures,
@@ -282,7 +285,7 @@ export const findCredentialSdJwt = (
282
285
 
283
286
  return {
284
287
  matchedEvaluation: evaluatedDisclosure,
285
- matchedKeyTag: keyTag,
288
+ cryptoContext,
286
289
  matchedCredential: credential,
287
290
  };
288
291
  } catch {
@@ -319,9 +322,9 @@ export const evaluateInputDescriptors: EvaluateInputDescriptors = async (
319
322
  ) => {
320
323
  // We need decode SD-JWT credentials for evaluation
321
324
  const decodedSdJwtCredentials =
322
- credentialsSdJwt?.map(([keyTag, credential]) => {
325
+ credentialsSdJwt?.map(([cryptoContext, credential]) => {
323
326
  const { sdJwt, disclosures } = decode(credential);
324
- return { keyTag, credential, sdJwt, disclosures };
327
+ return { cryptoContext, credential, sdJwt, disclosures };
325
328
  }) || [];
326
329
 
327
330
  return Promise.all(
@@ -336,14 +339,14 @@ export const evaluateInputDescriptors: EvaluateInputDescriptors = async (
336
339
  ]);
337
340
  }
338
341
 
339
- const { matchedEvaluation, matchedKeyTag, matchedCredential } =
342
+ const { matchedEvaluation, cryptoContext, matchedCredential } =
340
343
  findCredentialSdJwt(descriptor, decodedSdJwtCredentials);
341
344
 
342
345
  return {
343
346
  evaluatedDisclosure: matchedEvaluation,
344
347
  inputDescriptor: descriptor,
345
348
  credential: matchedCredential,
346
- keyTag: matchedKeyTag,
349
+ cryptoContext,
347
350
  };
348
351
  }
349
352
 
@@ -383,7 +386,7 @@ export const prepareLegacyRemotePresentations: PrepareLegacyRemotePresentations
383
386
  const { vp_token } = await prepareVpToken(nonce, client_id, [
384
387
  item.credential,
385
388
  item.requestedClaims,
386
- createCryptoContextFor(item.keyTag),
389
+ item.cryptoContext,
387
390
  ]);
388
391
 
389
392
  return {
@@ -30,7 +30,6 @@ export type LegacyRemotePresentation = {
30
30
  export type RemotePresentation = {
31
31
  requestedClaims: string[];
32
32
  credentialId: string;
33
- format: string;
34
33
  vpToken: string;
35
34
  };
36
35
 
@@ -97,7 +96,7 @@ export const RequestObject = z.object({
97
96
  state: z.string().optional(),
98
97
  nonce: z.string(),
99
98
  response_uri: z.string(),
100
- response_uri_method: z.string().optional(),
99
+ request_uri_method: z.string().optional(),
101
100
  response_type: z.literal("vp_token"),
102
101
  response_mode: z.literal("direct_post.jwt"),
103
102
  client_id: z.string(),