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

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 (122) hide show
  1. package/lib/commonjs/credential/issuance/03-start-user-authorization.js +38 -24
  2. package/lib/commonjs/credential/issuance/03-start-user-authorization.js.map +1 -1
  3. package/lib/commonjs/credential/issuance/05-authorize-access.js +6 -10
  4. package/lib/commonjs/credential/issuance/05-authorize-access.js.map +1 -1
  5. package/lib/commonjs/credential/issuance/06-obtain-credential.js +43 -11
  6. package/lib/commonjs/credential/issuance/06-obtain-credential.js.map +1 -1
  7. package/lib/commonjs/credential/issuance/07-verify-and-parse-credential.js +51 -48
  8. package/lib/commonjs/credential/issuance/07-verify-and-parse-credential.js.map +1 -1
  9. package/lib/commonjs/credential/issuance/README.md +34 -13
  10. package/lib/commonjs/credential/issuance/const.js +1 -1
  11. package/lib/commonjs/credential/issuance/types.js +16 -10
  12. package/lib/commonjs/credential/issuance/types.js.map +1 -1
  13. package/lib/commonjs/credential/presentation/07-evaluate-dcql-query.js +4 -4
  14. package/lib/commonjs/credential/presentation/07-evaluate-input-descriptor.js +3 -3
  15. package/lib/commonjs/credential/status/README.md +0 -1
  16. package/lib/commonjs/sd-jwt/__test__/index.test.js +11 -15
  17. package/lib/commonjs/sd-jwt/__test__/index.test.js.map +1 -1
  18. package/lib/commonjs/sd-jwt/__test__/types.test.js +5 -2
  19. package/lib/commonjs/sd-jwt/__test__/types.test.js.map +1 -1
  20. package/lib/commonjs/sd-jwt/__test__/utils.test.js +37 -0
  21. package/lib/commonjs/sd-jwt/__test__/utils.test.js.map +1 -0
  22. package/lib/commonjs/sd-jwt/index.js +20 -0
  23. package/lib/commonjs/sd-jwt/index.js.map +1 -1
  24. package/lib/commonjs/sd-jwt/types.js +51 -4
  25. package/lib/commonjs/sd-jwt/types.js.map +1 -1
  26. package/lib/commonjs/sd-jwt/utils.js +64 -0
  27. package/lib/commonjs/sd-jwt/utils.js.map +1 -0
  28. package/lib/commonjs/trust/types.js +18 -13
  29. package/lib/commonjs/trust/types.js.map +1 -1
  30. package/lib/commonjs/utils/par.js +32 -22
  31. package/lib/commonjs/utils/par.js.map +1 -1
  32. package/lib/commonjs/utils/pop.js +1 -1
  33. package/lib/commonjs/utils/pop.js.map +1 -1
  34. package/lib/commonjs/wallet-instance-attestation/types.js +5 -1
  35. package/lib/commonjs/wallet-instance-attestation/types.js.map +1 -1
  36. package/lib/module/credential/issuance/03-start-user-authorization.js +38 -24
  37. package/lib/module/credential/issuance/03-start-user-authorization.js.map +1 -1
  38. package/lib/module/credential/issuance/05-authorize-access.js +6 -10
  39. package/lib/module/credential/issuance/05-authorize-access.js.map +1 -1
  40. package/lib/module/credential/issuance/06-obtain-credential.js +44 -12
  41. package/lib/module/credential/issuance/06-obtain-credential.js.map +1 -1
  42. package/lib/module/credential/issuance/07-verify-and-parse-credential.js +51 -48
  43. package/lib/module/credential/issuance/07-verify-and-parse-credential.js.map +1 -1
  44. package/lib/module/credential/issuance/README.md +34 -13
  45. package/lib/module/credential/issuance/const.js +1 -1
  46. package/lib/module/credential/issuance/types.js +12 -8
  47. package/lib/module/credential/issuance/types.js.map +1 -1
  48. package/lib/module/credential/presentation/07-evaluate-dcql-query.js +4 -4
  49. package/lib/module/credential/presentation/07-evaluate-input-descriptor.js +3 -3
  50. package/lib/module/credential/status/README.md +0 -1
  51. package/lib/module/sd-jwt/__test__/index.test.js +11 -16
  52. package/lib/module/sd-jwt/__test__/index.test.js.map +1 -1
  53. package/lib/module/sd-jwt/__test__/types.test.js +5 -2
  54. package/lib/module/sd-jwt/__test__/types.test.js.map +1 -1
  55. package/lib/module/sd-jwt/__test__/utils.test.js +35 -0
  56. package/lib/module/sd-jwt/__test__/utils.test.js.map +1 -0
  57. package/lib/module/sd-jwt/index.js +1 -0
  58. package/lib/module/sd-jwt/index.js.map +1 -1
  59. package/lib/module/sd-jwt/types.js +50 -3
  60. package/lib/module/sd-jwt/types.js.map +1 -1
  61. package/lib/module/sd-jwt/utils.js +57 -0
  62. package/lib/module/sd-jwt/utils.js.map +1 -0
  63. package/lib/module/trust/types.js +18 -13
  64. package/lib/module/trust/types.js.map +1 -1
  65. package/lib/module/utils/par.js +29 -20
  66. package/lib/module/utils/par.js.map +1 -1
  67. package/lib/module/utils/pop.js +1 -1
  68. package/lib/module/utils/pop.js.map +1 -1
  69. package/lib/module/wallet-instance-attestation/types.js +5 -1
  70. package/lib/module/wallet-instance-attestation/types.js.map +1 -1
  71. package/lib/typescript/client/generated/wallet-provider.d.ts +12 -12
  72. package/lib/typescript/credential/issuance/01-start-flow.d.ts +2 -2
  73. package/lib/typescript/credential/issuance/01-start-flow.d.ts.map +1 -1
  74. package/lib/typescript/credential/issuance/03-start-user-authorization.d.ts +7 -6
  75. package/lib/typescript/credential/issuance/03-start-user-authorization.d.ts.map +1 -1
  76. package/lib/typescript/credential/issuance/05-authorize-access.d.ts.map +1 -1
  77. package/lib/typescript/credential/issuance/06-obtain-credential.d.ts +10 -5
  78. package/lib/typescript/credential/issuance/06-obtain-credential.d.ts.map +1 -1
  79. package/lib/typescript/credential/issuance/07-verify-and-parse-credential.d.ts +3 -2
  80. package/lib/typescript/credential/issuance/07-verify-and-parse-credential.d.ts.map +1 -1
  81. package/lib/typescript/credential/issuance/const.d.ts +1 -1
  82. package/lib/typescript/credential/issuance/types.d.ts +46 -26
  83. package/lib/typescript/credential/issuance/types.d.ts.map +1 -1
  84. package/lib/typescript/pid/sd-jwt/types.d.ts +7 -7
  85. package/lib/typescript/sd-jwt/__test__/utils.test.d.ts +2 -0
  86. package/lib/typescript/sd-jwt/__test__/utils.test.d.ts.map +1 -0
  87. package/lib/typescript/sd-jwt/index.d.ts +21 -8
  88. package/lib/typescript/sd-jwt/index.d.ts.map +1 -1
  89. package/lib/typescript/sd-jwt/types.d.ts +194 -12
  90. package/lib/typescript/sd-jwt/types.d.ts.map +1 -1
  91. package/lib/typescript/sd-jwt/utils.d.ts +18 -0
  92. package/lib/typescript/sd-jwt/utils.d.ts.map +1 -0
  93. package/lib/typescript/trust/build-chain.d.ts +30 -14
  94. package/lib/typescript/trust/build-chain.d.ts.map +1 -1
  95. package/lib/typescript/trust/types.d.ts +322 -158
  96. package/lib/typescript/trust/types.d.ts.map +1 -1
  97. package/lib/typescript/utils/par.d.ts +29 -13
  98. package/lib/typescript/utils/par.d.ts.map +1 -1
  99. package/lib/typescript/wallet-instance-attestation/types.d.ts +9 -9
  100. package/lib/typescript/wallet-instance-attestation/types.d.ts.map +1 -1
  101. package/package.json +1 -1
  102. package/src/credential/issuance/01-start-flow.ts +2 -2
  103. package/src/credential/issuance/03-start-user-authorization.ts +57 -38
  104. package/src/credential/issuance/05-authorize-access.ts +5 -11
  105. package/src/credential/issuance/06-obtain-credential.ts +53 -23
  106. package/src/credential/issuance/07-verify-and-parse-credential.ts +54 -62
  107. package/src/credential/issuance/README.md +34 -13
  108. package/src/credential/issuance/const.ts +1 -1
  109. package/src/credential/issuance/types.ts +18 -8
  110. package/src/credential/presentation/07-evaluate-dcql-query.ts +4 -4
  111. package/src/credential/presentation/07-evaluate-input-descriptor.ts +3 -3
  112. package/src/credential/status/README.md +0 -1
  113. package/src/sd-jwt/__test__/index.test.ts +8 -29
  114. package/src/sd-jwt/__test__/types.test.ts +6 -2
  115. package/src/sd-jwt/__test__/utils.test.ts +37 -0
  116. package/src/sd-jwt/index.ts +2 -0
  117. package/src/sd-jwt/types.ts +49 -2
  118. package/src/sd-jwt/utils.ts +73 -0
  119. package/src/trust/types.ts +23 -17
  120. package/src/utils/par.ts +37 -21
  121. package/src/utils/pop.ts +1 -1
  122. package/src/wallet-instance-attestation/types.ts +3 -1
@@ -9,10 +9,14 @@ import type { JWK } from "../../utils/jwk";
9
9
  import type { ObtainCredential } from "./06-obtain-credential";
10
10
  import { LogLevel, Logger } from "../../utils/logging";
11
11
 
12
+ type IssuerConf = Out<EvaluateIssuerTrust>["issuerConf"];
13
+ type CredentialConf =
14
+ IssuerConf["openid_credential_issuer"]["credential_configurations_supported"][string];
15
+
12
16
  export type VerifyAndParseCredential = (
13
- issuerConf: Out<EvaluateIssuerTrust>["issuerConf"],
17
+ issuerConf: IssuerConf,
14
18
  credential: Out<ObtainCredential>["credential"],
15
- format: Out<ObtainCredential>["format"],
19
+ credentialConfigurationId: string,
16
20
  context: {
17
21
  credentialCryptoContext: CryptoContext;
18
22
  /**
@@ -54,54 +58,35 @@ type DecodedSdJwtCredential = Out<typeof verifySdJwt> & {
54
58
  };
55
59
 
56
60
  const parseCredentialSdJwt = (
57
- // the list of supported credentials, as defined in the issuer configuration
58
- credentials_supported: Out<EvaluateIssuerTrust>["issuerConf"]["openid_credential_issuer"]["credential_configurations_supported"],
61
+ // The credential configuration to use to parse the provided credential
62
+ credentialConfig: CredentialConf,
59
63
  { sdJwt, disclosures }: DecodedSdJwtCredential,
60
64
  ignoreMissingAttributes: boolean = false,
61
65
  includeUndefinedAttributes: boolean = false
62
66
  ): ParsedCredential => {
63
- const credentialSubject = credentials_supported[sdJwt.payload.vct];
64
-
65
- if (!credentialSubject) {
66
- Logger.log(
67
- LogLevel.ERROR,
68
- `Credential type not supported by the issuer: ${sdJwt.payload.vct}`
69
- );
70
- throw new IoWalletError("Credential type not supported by the issuer");
67
+ if (credentialConfig.format !== sdJwt.header.typ) {
68
+ const message = `Received credential is of an unknwown type. Expected one of [${credentialConfig.format}], received '${sdJwt.header.typ}'`;
69
+ Logger.log(LogLevel.ERROR, message);
70
+ throw new IoWalletError(message);
71
71
  }
72
72
 
73
- if (credentialSubject.format !== sdJwt.header.typ) {
74
- Logger.log(
75
- LogLevel.ERROR,
76
- `Received credential is of an unknwown type. Expected one of [${credentialSubject.format}], received '${sdJwt.header.typ}'`
77
- );
78
- throw new IoWalletError(
79
- `Received credential is of an unknwown type. Expected one of [${credentialSubject.format}], received '${sdJwt.header.typ}', `
80
- );
81
- }
82
-
83
- // transfrom a record { key: value } in an iterable of pairs [key, value]
84
- if (!credentialSubject.claims) {
73
+ if (!credentialConfig.claims) {
85
74
  Logger.log(LogLevel.ERROR, "Missing claims in the credential subject");
86
75
  throw new IoWalletError("Missing claims in the credential subject"); // TODO [SIW-1268]: should not be optional
87
76
  }
88
- const attrDefinitions = Object.entries(credentialSubject.claims);
77
+ const attrDefinitions = credentialConfig.claims;
89
78
 
90
79
  // the key of the attribute defintion must match the disclosure's name
91
80
  const attrsNotInDisclosures = attrDefinitions.filter(
92
- ([attrKey]) => !disclosures.some(([, name]) => name === attrKey)
81
+ (definition) => !disclosures.some(([, name]) => name === definition.path[0]) // Ignore nested paths for now, see https://openid.net/specs/openid-4-verifiable-credential-issuance-1_0-15.html#name-claims-path-pointer
93
82
  );
94
83
  if (attrsNotInDisclosures.length > 0) {
95
- const missing = attrsNotInDisclosures.map((_) => _[0 /* key */]).join(", ");
84
+ const missing = attrsNotInDisclosures.map((_) => _.path[0]).join(", ");
96
85
  const received = disclosures.map((_) => _[1 /* name */]).join(", ");
97
86
  if (!ignoreMissingAttributes) {
98
- Logger.log(
99
- LogLevel.ERROR,
100
- `Some attributes are missing in the credential. Missing: [${missing}], received: [${received}]`
101
- );
102
- throw new IoWalletError(
103
- `Some attributes are missing in the credential. Missing: [${missing}], received: [${received}]`
104
- );
87
+ const message = `Some attributes are missing in the credential. Missing: [${missing}], received: [${received}]`;
88
+ Logger.log(LogLevel.ERROR, message);
89
+ throw new IoWalletError(message);
105
90
  }
106
91
  }
107
92
 
@@ -111,13 +96,13 @@ const parseCredentialSdJwt = (
111
96
  attrDefinitions
112
97
  // retrieve the value from the disclosure set
113
98
  .map(
114
- ([attrKey, definition]) =>
99
+ ({ path, ...definition }) =>
115
100
  [
116
- attrKey,
101
+ path[0],
117
102
  {
118
103
  ...definition,
119
104
  value: disclosures.find(
120
- (_) => _[1 /* name */] === attrKey
105
+ (_) => _[1 /* name */] === path[0]
121
106
  )?.[2 /* value */],
122
107
  },
123
108
  ] as const
@@ -186,30 +171,18 @@ async function verifyCredentialSdJwt(
186
171
  const { cnf } = decodedCredential.sdJwt.payload;
187
172
 
188
173
  if (!cnf.jwk.kid || cnf.jwk.kid !== holderBindingKey.kid) {
189
- Logger.log(
190
- LogLevel.ERROR,
191
- `Failed to verify holder binding, expected kid: ${holderBindingKey.kid}, got: ${decodedCredential.sdJwt.payload.cnf.jwk.kid}`
192
- );
193
- throw new IoWalletError(
194
- `Failed to verify holder binding, expected kid: ${holderBindingKey.kid}, got: ${decodedCredential.sdJwt.payload.cnf.jwk.kid}`
195
- );
174
+ const message = `Failed to verify holder binding, expected kid: ${holderBindingKey.kid}, got: ${decodedCredential.sdJwt.payload.cnf.jwk.kid}`;
175
+ Logger.log(LogLevel.ERROR, message);
176
+ throw new IoWalletError(message);
196
177
  }
197
178
 
198
179
  return decodedCredential;
199
180
  }
200
181
 
201
- // utility type that specialize VerifyAndParseCredential for given format
202
- type WithFormat<Format extends Parameters<VerifyAndParseCredential>[2]> = (
203
- _0: Parameters<VerifyAndParseCredential>[0],
204
- _1: Parameters<VerifyAndParseCredential>[1],
205
- _2: Format,
206
- _3: Parameters<VerifyAndParseCredential>[3]
207
- ) => ReturnType<VerifyAndParseCredential>;
208
-
209
- const verifyAndParseCredentialSdJwt: WithFormat<"vc+sd-jwt"> = async (
182
+ const verifyAndParseCredentialSdJwt: VerifyAndParseCredential = async (
210
183
  issuerConf,
211
184
  credential,
212
- _,
185
+ credentialConfigurationId,
213
186
  {
214
187
  credentialCryptoContext,
215
188
  ignoreMissingAttributes,
@@ -224,8 +197,21 @@ const verifyAndParseCredentialSdJwt: WithFormat<"vc+sd-jwt"> = async (
224
197
 
225
198
  Logger.log(LogLevel.DEBUG, `Decoded credential: ${JSON.stringify(decoded)}`);
226
199
 
200
+ const credentialConfig =
201
+ issuerConf.openid_credential_issuer.credential_configurations_supported[
202
+ credentialConfigurationId
203
+ ];
204
+
205
+ if (!credentialConfig) {
206
+ Logger.log(
207
+ LogLevel.ERROR,
208
+ `Credential type not supported by the issuer: ${credentialConfigurationId}`
209
+ );
210
+ throw new IoWalletError("Credential type not supported by the issuer");
211
+ }
212
+
227
213
  const parsedCredential = parseCredentialSdJwt(
228
- issuerConf.openid_credential_issuer.credential_configurations_supported,
214
+ credentialConfig,
229
215
  decoded,
230
216
  ignoreMissingAttributes,
231
217
  includeUndefinedAttributes
@@ -251,7 +237,7 @@ const verifyAndParseCredentialSdJwt: WithFormat<"vc+sd-jwt"> = async (
251
237
  * Verify and parse an encoded credential.
252
238
  * @param issuerConf The Issuer configuration returned by {@link evaluateIssuerTrust}
253
239
  * @param credential The encoded credential returned by {@link obtainCredential}
254
- * @param format The format of the credentual returned by {@link obtainCredential}
240
+ * @param credentialConfigurationId The credential configuration ID that defines the provided credential
255
241
  * @param context.credentialCryptoContext The crypto context used to obtain the credential in {@link obtainCredential}
256
242
  * @param context.ignoreMissingAttributes Skip error when attributes declared in the issuer configuration are not found within disclosures
257
243
  * @param context.includeUndefinedAttributes Include attributes not explicitly declared in the issuer configuration
@@ -263,19 +249,25 @@ const verifyAndParseCredentialSdJwt: WithFormat<"vc+sd-jwt"> = async (
263
249
  export const verifyAndParseCredential: VerifyAndParseCredential = async (
264
250
  issuerConf,
265
251
  credential,
266
- format,
252
+ credentialConfigurationId,
267
253
  context
268
254
  ) => {
269
- if (format === "vc+sd-jwt") {
270
- Logger.log(LogLevel.DEBUG, "Parsing credential in vc+sd-jwt format");
255
+ const format =
256
+ issuerConf.openid_credential_issuer.credential_configurations_supported[
257
+ credentialConfigurationId
258
+ ]?.format;
259
+
260
+ if (format === "dc+sd-jwt") {
261
+ Logger.log(LogLevel.DEBUG, "Parsing credential in dc+sd-jwt format");
271
262
  return verifyAndParseCredentialSdJwt(
272
263
  issuerConf,
273
264
  credential,
274
- format,
265
+ credentialConfigurationId,
275
266
  context
276
267
  );
277
268
  }
278
269
 
279
- Logger.log(LogLevel.ERROR, `Unsupported credential format: ${format}`);
280
- throw new IoWalletError(`Unsupported credential format: ${format}`);
270
+ const message = `Unsupported credential format: ${format}`;
271
+ Logger.log(LogLevel.ERROR, message);
272
+ throw new IoWalletError(message);
281
273
  };
@@ -6,7 +6,7 @@ There's a fork in the flow which is based on the type of the credential that is
6
6
  This is due to the fact that eID credentials require a different authorization flow than other credentials, which is accomplished by a strong authentication method like SPID or CIE.
7
7
  Credentials instead require a simpler authorization flow and they require other credentials to be presented in order to be issued.
8
8
 
9
- The supported credentials are defined in the entity configuration of the issuer which is evaluted and parsed in the `evaluateIssuerTrust` step.
9
+ The supported credentials are defined in the entity configuration of the issuer which is evaluted and parsed in the `evaluateIssuerTrust` step. Available credentials are identified with a unique `credential_configuration_id`, that must be used when requesting authorization. The Authorization Server returns an array of **credential identifiers** that map to the `credential_configuration_id` provided: to obtain the credential, one of the credential identifiers (or all of them) must be requested to the credential endpoint.
10
10
 
11
11
  ## Sequence Diagram
12
12
 
@@ -72,6 +72,8 @@ 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
+
75
77
  // Retrieve the integrity key tag from the store and create its context
76
78
  const integrityKeyTag = "example"; // Let's assume this is the key tag used to create the wallet instance
77
79
  const integrityContext = getIntegrityContext(integrityKeyTag);
@@ -251,11 +253,10 @@ const credentialCryptoContext = createCryptoContextFor(credentialKeyTag);
251
253
  // Start the issuance flow
252
254
  const startFlow: Credential.Issuance.StartFlow = () => ({
253
255
  issuerUrl: WALLET_EID_PROVIDER_BASE_URL,
254
- credentialType: "PersonIdentificationData",
255
- appFetch,
256
+ credentialId: "dc_sd_jwt_PersonIdentificationData",
256
257
  });
257
258
 
258
- const { issuerUrl } = startFlow();
259
+ const { issuerUrl, credentialId } = startFlow();
259
260
 
260
261
  // Evaluate issuer trust
261
262
  const { issuerConf } = await Credential.Issuance.evaluateIssuerTrust(
@@ -265,12 +266,16 @@ const { issuerConf } = await Credential.Issuance.evaluateIssuerTrust(
265
266
 
266
267
  // Start user authorization
267
268
  const { issuerRequestUri, clientId, codeVerifier, credentialDefinition } =
268
- await Credential.Issuance.startUserAuthorization(issuerConf, credentialType, {
269
- walletInstanceAttestation,
270
- redirectUri,
271
- wiaCryptoContext,
272
- appFetch,
273
- });
269
+ await Credential.Issuance.startUserAuthorization(
270
+ issuerConf,
271
+ [credentialId], // Request authorization for one or more credentials
272
+ {
273
+ walletInstanceAttestation,
274
+ redirectUri,
275
+ wiaCryptoContext,
276
+ appFetch,
277
+ }
278
+ );
274
279
 
275
280
  // Complete the authorization process with query mode with the authorizationContext which opens the browser
276
281
  const { code } =
@@ -301,12 +306,27 @@ const { accessToken } = await Credential.Issuance.authorizeAccess(
301
306
  }
302
307
  );
303
308
 
309
+
310
+ const [pidCredentialDefinition] = credentialDefinition;
311
+
312
+ // Extract the credential_identifier(s) from the access token
313
+ // For each one of them, a credential can be obtained by calling `obtainCredential`
314
+ const { credential_configuration_id, credential_identifiers } =
315
+ accessToken.authorization_details.find(
316
+ (authDetails) =>
317
+ authDetails.credential_configuration_id ===
318
+ pidCredentialDefinition.credential_configuration_id
319
+ );
320
+
304
321
  // Obtain che eID credential
305
322
  const { credential, format } = await Credential.Issuance.obtainCredential(
306
323
  issuerConf,
307
324
  accessToken,
308
325
  clientId,
309
- credentialDefinition,
326
+ {
327
+ credential_configuration_id,
328
+ credential_identifier: credential_identifiers.at(0),
329
+ },
310
330
  {
311
331
  credentialCryptoContext,
312
332
  dPopCryptoContext,
@@ -318,15 +338,16 @@ const { credential, format } = await Credential.Issuance.obtainCredential(
318
338
  const { parsedCredential, issuedAt, expiration } = await Credential.Issuance.verifyAndParseCredential(
319
339
  issuerConf,
320
340
  credential,
321
- format,
341
+ credential_configuration_id,
322
342
  { credentialCryptoContext }
323
343
  );
324
344
 
325
345
  return {
326
346
  parsedCredential,
327
347
  credential,
348
+ credentialConfigurationId: credential_configuration_id
349
+ credentialType: "PersonIdentificationData",
328
350
  keyTag: credentialKeyTag,
329
- credentialType,
330
351
  issuedAt,
331
352
  expiration
332
353
  };
@@ -6,6 +6,6 @@ export type SupportedCredentialFormat = z.infer<
6
6
  typeof SupportedCredentialFormat
7
7
  >;
8
8
  export const SupportedCredentialFormat = z.union([
9
- z.literal("vc+sd-jwt"),
9
+ z.literal("dc+sd-jwt"),
10
10
  z.literal("vc+mdoc-cbor"),
11
11
  ]);
@@ -1,14 +1,17 @@
1
- import { AuthorizationDetail } from "../../utils/par";
2
1
  import * as z from "zod";
3
- import { SupportedCredentialFormat } from "./const";
2
+
3
+ export type AuthorizationDetail = z.infer<typeof AuthorizationDetail>;
4
+ export const AuthorizationDetail = z.object({
5
+ type: z.literal("openid_credential"),
6
+ credential_configuration_id: z.string(),
7
+ credential_identifiers: z.array(z.string()),
8
+ });
4
9
 
5
10
  export type TokenResponse = z.infer<typeof TokenResponse>;
6
11
 
7
12
  export const TokenResponse = z.object({
8
13
  access_token: z.string(),
9
14
  authorization_details: z.array(AuthorizationDetail),
10
- c_nonce: z.string(),
11
- c_nonce_expires_in: z.number(),
12
15
  expires_in: z.number(),
13
16
  token_type: z.string(),
14
17
  });
@@ -16,10 +19,12 @@ export const TokenResponse = z.object({
16
19
  export type CredentialResponse = z.infer<typeof CredentialResponse>;
17
20
 
18
21
  export const CredentialResponse = z.object({
19
- c_nonce: z.string(),
20
- c_nonce_expires_in: z.number(),
21
- credential: z.string(),
22
- format: SupportedCredentialFormat,
22
+ credentials: z.array(
23
+ z.object({
24
+ credential: z.string(),
25
+ })
26
+ ),
27
+ notification_id: z.string().optional(),
23
28
  });
24
29
 
25
30
  /**
@@ -30,3 +35,8 @@ export const ResponseUriResultShape = z.object({
30
35
  });
31
36
 
32
37
  export type ResponseMode = "query" | "form_post.jwt";
38
+
39
+ export type NonceResponse = z.infer<typeof NonceResponse>;
40
+ export const NonceResponse = z.object({
41
+ c_nonce: z.string(),
42
+ });
@@ -56,7 +56,7 @@ const mapCredentialToObject = (jwt: string) => {
56
56
  const credentialFormat = sdJwt.header.typ;
57
57
 
58
58
  // TODO [SIW-2082]: support MDOC credentials
59
- if (credentialFormat !== "vc+sd-jwt") {
59
+ if (credentialFormat !== "dc+sd-jwt") {
60
60
  throw new Error(`Unsupported credential format: ${credentialFormat}`);
61
61
  }
62
62
 
@@ -100,7 +100,7 @@ const extractMissingCredentials = (
100
100
  ): NotFoundDetail[] => {
101
101
  return getDcqlQueryFailedMatches(queryResult).map(([id]) => {
102
102
  const credential = originalQuery.credentials.find((c) => c.id === id);
103
- if (credential?.format !== "vc+sd-jwt") {
103
+ if (credential?.format !== "dc+sd-jwt") {
104
104
  throw new Error("Unsupported format"); // TODO [SIW-2082]: support MDOC credentials
105
105
  }
106
106
  return { id, vctValues: credential.meta?.vct_values };
@@ -135,7 +135,7 @@ export const evaluateDcqlQuery: EvaluateDcqlQuery = (
135
135
  );
136
136
 
137
137
  return getDcqlQueryMatches(queryResult).map(([id, match]) => {
138
- if (match.output.credential_format !== "vc+sd-jwt") {
138
+ if (match.output.credential_format !== "dc+sd-jwt") {
139
139
  throw new Error("Unsupported format"); // TODO [SIW-2082]: support MDOC credentials
140
140
  }
141
141
  const { vct, claims } = match.output;
@@ -192,7 +192,7 @@ export const prepareRemotePresentations: PrepareRemotePresentations = async (
192
192
  credentialId: item.id,
193
193
  requestedClaims: item.requestedClaims,
194
194
  vpToken: vp_token,
195
- format: "vc+sd-jwt",
195
+ format: "dc+sd-jwt",
196
196
  };
197
197
  })
198
198
  );
@@ -326,7 +326,7 @@ export const evaluateInputDescriptors: EvaluateInputDescriptors = async (
326
326
 
327
327
  return Promise.all(
328
328
  inputDescriptors.map(async (descriptor) => {
329
- if (descriptor.format?.["vc+sd-jwt"]) {
329
+ if (descriptor.format?.["dc+sd-jwt"]) {
330
330
  if (!decodedSdJwtCredentials.length) {
331
331
  throw new CredentialsNotFoundError([
332
332
  {
@@ -379,7 +379,7 @@ export const prepareLegacyRemotePresentations: PrepareLegacyRemotePresentations
379
379
  credentialAndDescriptors.map(async (item) => {
380
380
  const descriptor = item.inputDescriptor;
381
381
 
382
- if (descriptor.format?.["vc+sd-jwt"]) {
382
+ if (descriptor.format?.["dc+sd-jwt"]) {
383
383
  const { vp_token } = await prepareVpToken(nonce, client_id, [
384
384
  item.credential,
385
385
  item.requestedClaims,
@@ -390,7 +390,7 @@ export const prepareLegacyRemotePresentations: PrepareLegacyRemotePresentations
390
390
  requestedClaims: item.requestedClaims,
391
391
  inputDescriptor: descriptor,
392
392
  vpToken: vp_token,
393
- format: "vc+sd-jwt",
393
+ format: "dc+sd-jwt",
394
394
  };
395
395
  }
396
396
 
@@ -60,7 +60,6 @@ const { parsedStatusAttestation } =
60
60
  return {
61
61
  statusAttestation: res.statusAttestation,
62
62
  parsedStatusAttestation,
63
- credentialType,
64
63
  };
65
64
  ```
66
65
 
@@ -3,39 +3,14 @@ import { decode, disclose } from "../index";
3
3
 
4
4
  import { encodeBase64, decodeBase64 } from "@pagopa/io-react-native-jwt";
5
5
  import { SdJwt4VC } from "../types";
6
+ import { pid } from "../__mocks__/sd-jwt";
6
7
 
7
- // Examples from https://www.ietf.org/archive/id/draft-terbu-sd-jwt-vc-02.html#name-example-4
8
- // but adapted to adhere to format declared in https://italia.github.io/eudi-wallet-it-docs/versione-corrente/en/pid-eaa-data-model.html#id2
9
- // In short, the token is a Frankenstein composed as follows:
10
- // - the header is taken from the italian specification, with kid and alg valued according to the signing keys
11
- // - disclosures are taken from the SD-JWT-4-VC standard
12
- // - payload is taken from the italian specification, but _sd are compiled with:
13
- // - "address" is used as verification._sd
14
- // - all others disclosures are in claims._sd
15
- const token =
16
- "eyJraWQiOiItRl82VWdhOG4zVmVnalkyVTdZVUhLMXpMb2FELU5QVGM2M1JNSVNuTGF3IiwidHlwIjoidmMrc2Qtand0IiwiYWxnIjoiRVMyNTYifQ.eyJfc2QiOlsiMHExRDVKbWF2NnBRYUVoX0pfRmN2X3VOTk1RSWdDeWhRT3hxbFk0bDNxVSIsIktDSi1BVk52ODhkLXhqNnNVSUFPSnhGbmJVaDNySFhES2tJSDFsRnFiUnMiLCJNOWxvOVl4RE5JWHJBcTJxV2VpQ0E0MHpwSl96WWZGZFJfNEFFQUxjUnRVIiwiY3pnalVrMG5xUkNzd1NoQ2hDamRTNkExLXY0N2RfcVRDU0ZJdklIaE1vSSIsIm5HblFyN2NsbTN0ZlRwOHlqTF91SHJEU090elIyUFZiOFM3R2VMZEFxQlEiLCJ4TklWd2xwU3NhWjhDSlNmMGd6NXhfNzVWUldXYzZWMW1scGVqZENycVVzIl0sInN1YiI6IjIxNmY4OTQ2LTllY2ItNDgxOS05MzA5LWMwNzZmMzRhN2UxMSIsIl9zZF9hbGciOiJzaGEtMjU2IiwidmN0IjoiUGVyc29uSWRlbnRpZmljYXRpb25EYXRhIiwiaXNzIjoiaHR0cHM6Ly9wcmUuZWlkLndhbGxldC5pcHpzLml0IiwiY25mIjp7Imp3ayI6eyJrdHkiOiJFQyIsImNydiI6IlAtMjU2Iiwia2lkIjoiUnYzVy1FaUtwdkJUeWs1eVp4dnJldi03TURCNlNselVDQm9fQ1FqamRkVSIsIngiOiIwV294N1F0eVBxQnlnMzVNSF9YeUNjbmQ1TGUtSm0wQVhIbFVnREJBMDNZIiwieSI6ImVFaFZ2ZzFKUHFOZDNEVFNhNG1HREdCbHdZNk5QLUVaYkxiTkZYU1h3SWcifX0sImV4cCI6MTc1MTU0NjU3Niwic3RhdHVzIjp7InN0YXR1c19hdHRlc3RhdGlvbiI6eyJjcmVkZW50aWFsX2hhc2hfYWxnIjoic2hhLTI1NiJ9fX0.qXHA2oqr8trX4fGxpxpUft2GX380TM3pzfo1MYAsDjUC8HsODA-4rdRWAvDe2zYP57x4tJU7eiABkd1Kmln9yQ~WyJrSkRFUDhFYU5URU1CRE9aelp6VDR3IiwidW5pcXVlX2lkIiwiVElOSVQtTFZMREFBODVUNTBHNzAyQiJd~WyJ6SUF5VUZ2UGZJcEUxekJxeEk1aGFRIiwiYmlydGhfZGF0ZSIsIjE5ODUtMTItMTAiXQ~WyJHcjNSM3MyOTBPa1FVbS1ORlR1OTZBIiwidGF4X2lkX2NvZGUiLCJUSU5JVC1MVkxEQUE4NVQ1MEc3MDJCIl0~WyJHeE9SYWxNQWVsZlowZWRGSmpqWVV3IiwiZ2l2ZW5fbmFtZSIsIkFkYSJd~WyJfdlY1UklrbDBJT0VYS290czlrdDF3IiwiZmFtaWx5X25hbWUiLCJMb3ZlbGFjZSJd~WyJDajV0Y2NSNzJKd3J6ZTJUVzRhLXdnIiwiaWF0IiwxNzIwMDEwNTc1XQ";
17
-
18
- const unsigned =
19
- "eyJraWQiOiItRl82VWdhOG4zVmVnalkyVTdZVUhLMXpMb2FELU5QVGM2M1JNSVNuTGF3IiwidHlwIjoidmMrc2Qtand0IiwiYWxnIjoiRVMyNTYifQ.eyJfc2QiOlsiMHExRDVKbWF2NnBRYUVoX0pfRmN2X3VOTk1RSWdDeWhRT3hxbFk0bDNxVSIsIktDSi1BVk52ODhkLXhqNnNVSUFPSnhGbmJVaDNySFhES2tJSDFsRnFiUnMiLCJNOWxvOVl4RE5JWHJBcTJxV2VpQ0E0MHpwSl96WWZGZFJfNEFFQUxjUnRVIiwiY3pnalVrMG5xUkNzd1NoQ2hDamRTNkExLXY0N2RfcVRDU0ZJdklIaE1vSSIsIm5HblFyN2NsbTN0ZlRwOHlqTF91SHJEU090elIyUFZiOFM3R2VMZEFxQlEiLCJ4TklWd2xwU3NhWjhDSlNmMGd6NXhfNzVWUldXYzZWMW1scGVqZENycVVzIl0sInN1YiI6IjIxNmY4OTQ2LTllY2ItNDgxOS05MzA5LWMwNzZmMzRhN2UxMSIsIl9zZF9hbGciOiJzaGEtMjU2IiwidmN0IjoiUGVyc29uSWRlbnRpZmljYXRpb25EYXRhIiwiaXNzIjoiaHR0cHM6Ly9wcmUuZWlkLndhbGxldC5pcHpzLml0IiwiY25mIjp7Imp3ayI6eyJrdHkiOiJFQyIsImNydiI6IlAtMjU2Iiwia2lkIjoiUnYzVy1FaUtwdkJUeWs1eVp4dnJldi03TURCNlNselVDQm9fQ1FqamRkVSIsIngiOiIwV294N1F0eVBxQnlnMzVNSF9YeUNjbmQ1TGUtSm0wQVhIbFVnREJBMDNZIiwieSI6ImVFaFZ2ZzFKUHFOZDNEVFNhNG1HREdCbHdZNk5QLUVaYkxiTkZYU1h3SWcifX0sImV4cCI6MTc1MTU0NjU3Niwic3RhdHVzIjp7InN0YXR1c19hdHRlc3RhdGlvbiI6eyJjcmVkZW50aWFsX2hhc2hfYWxnIjoic2hhLTI1NiJ9fX0";
20
-
21
- const signature =
22
- "qXHA2oqr8trX4fGxpxpUft2GX380TM3pzfo1MYAsDjUC8HsODA-4rdRWAvDe2zYP57x4tJU7eiABkd1Kmln9yQ";
23
-
24
- const signed = `${unsigned}.${signature}`;
25
-
26
- const tokenizedDisclosures = [
27
- "WyJrSkRFUDhFYU5URU1CRE9aelp6VDR3IiwidW5pcXVlX2lkIiwiVElOSVQtTFZMREFBODVUNTBHNzAyQiJd",
28
- "WyJ6SUF5VUZ2UGZJcEUxekJxeEk1aGFRIiwiYmlydGhfZGF0ZSIsIjE5ODUtMTItMTAiXQ",
29
- "WyJHcjNSM3MyOTBPa1FVbS1ORlR1OTZBIiwidGF4X2lkX2NvZGUiLCJUSU5JVC1MVkxEQUE4NVQ1MEc3MDJCIl0",
30
- "WyJHeE9SYWxNQWVsZlowZWRGSmpqWVV3IiwiZ2l2ZW5fbmFtZSIsIkFkYSJd",
31
- "WyJfdlY1UklrbDBJT0VYS290czlrdDF3IiwiZmFtaWx5X25hbWUiLCJMb3ZlbGFjZSJd",
32
- "WyJDajV0Y2NSNzJKd3J6ZTJUVzRhLXdnIiwiaWF0IiwxNzIwMDEwNTc1XQ",
33
- ];
8
+ const { token, signed, tokenizedDisclosures } = pid;
34
9
 
35
10
  const sdJwt = {
36
11
  header: {
37
12
  kid: "-F_6Uga8n3VegjY2U7YUHK1zLoaD-NPTc63RMISnLaw",
38
- typ: "vc+sd-jwt",
13
+ typ: "dc+sd-jwt",
39
14
  alg: "ES256",
40
15
  },
41
16
  payload: {
@@ -50,7 +25,11 @@ const sdJwt = {
50
25
  sub: "216f8946-9ecb-4819-9309-c076f34a7e11",
51
26
  _sd_alg: "sha-256",
52
27
  vct: "PersonIdentificationData",
28
+ "vct#integrity":
29
+ "13e25888ac7b8a3a6d61440da787fccc81654e61085732bcacd89b36aec32675",
53
30
  iss: "https://pre.eid.wallet.ipzs.it",
31
+ issuing_country: "IT",
32
+ issuing_authority: "Istituto Poligrafico e Zecca dello Stato",
54
33
  cnf: {
55
34
  jwk: {
56
35
  kty: "EC",
@@ -62,7 +41,7 @@ const sdJwt = {
62
41
  },
63
42
  exp: 1751546576,
64
43
  status: {
65
- status_attestation: {
44
+ status_assertion: {
66
45
  credential_hash_alg: "sha-256",
67
46
  },
68
47
  },
@@ -5,7 +5,7 @@ describe("SdJwt4VC", () => {
5
5
  // example provided at https://italia.github.io/eidas-it-wallet-docs/en/pid-data-model.html
6
6
  const token = {
7
7
  header: {
8
- typ: "vc+sd-jwt",
8
+ typ: "dc+sd-jwt",
9
9
  alg: "RS512",
10
10
  kid: "dB67gL7ck3TFiIAf7N6_7SHvqk0MDYMEQcoGGlkUAAw",
11
11
  },
@@ -21,7 +21,11 @@ describe("SdJwt4VC", () => {
21
21
  sub: "216f8946-9ecb-4819-9309-c076f34a7e11",
22
22
  _sd_alg: "sha-256",
23
23
  vct: "PersonIdentificationData",
24
+ "vct#integrity":
25
+ "13e25888ac7b8a3a6d61440da787fccc81654e61085732bcacd89b36aec32675",
24
26
  iss: "https://pidprovider.example.com",
27
+ issuing_country: "IT",
28
+ issuing_authority: "Istituto Poligrafico e Zecca dello Stato",
25
29
  cnf: {
26
30
  jwk: {
27
31
  kty: "EC",
@@ -33,7 +37,7 @@ describe("SdJwt4VC", () => {
33
37
  },
34
38
  exp: 1751107255,
35
39
  status: {
36
- status_attestation: {
40
+ status_assertion: {
37
41
  credential_hash_alg: "sha-256",
38
42
  },
39
43
  },
@@ -0,0 +1,37 @@
1
+ import { getVerification } from "..";
2
+ import { pid } from "../__mocks__/sd-jwt";
3
+
4
+ const { signed, token } = pid;
5
+
6
+ describe("SD-JWT getVerification", () => {
7
+ it("extracts the verification claims correctly", () => {
8
+ const disclosure =
9
+ "WyJxTGxVdkNKY3hwX3d4MVY5dHFPbFFRIiwidmVyaWZpY2F0aW9uIix7ImV2aWRlbmNlIjpbeyJhdHRlc3RhdGlvbiI6eyJkYXRlX29mX2lzc3VhbmNlIjoiMjAyNS0wNi0yMyIsInZvdWNoZXIiOnsib3JnYW5pemF0aW9uIjoiTWluaXN0ZXJvIGRlbGwnSW50ZXJubyJ9LCJ0eXBlIjoiZGlnaXRhbF9hdHRlc3RhdGlvbiIsInJlZmVyZW5jZV9udW1iZXIiOiIxMjM0NTY3ODkifSwidGltZSI6IjIwMjUtMDYtMjNUMTM6MTQ6MjVaIiwidHlwZSI6InZvdWNoIn1dLCJ0cnVzdF9mcmFtZXdvcmsiOiJpdF9jaWUiLCJhc3N1cmFuY2VfbGV2ZWwiOiJoaWdoIn1d";
10
+ expect(getVerification(`${signed}~${disclosure}`)).toEqual({
11
+ evidence: [
12
+ {
13
+ attestation: {
14
+ date_of_issuance: "2025-06-23",
15
+ voucher: { organization: "Ministero dell'Interno" },
16
+ type: "digital_attestation",
17
+ reference_number: "123456789",
18
+ },
19
+ time: "2025-06-23T13:14:25Z",
20
+ type: "vouch",
21
+ },
22
+ ],
23
+ trust_framework: "it_cie",
24
+ assurance_level: "high",
25
+ });
26
+ });
27
+
28
+ it("returns undefined when the verification claim is not found", () => {
29
+ expect(getVerification(token)).toBeUndefined();
30
+ });
31
+
32
+ it("throws when the verification claim is invalid", () => {
33
+ const disclosure =
34
+ "WyJxTGxVdkNKY3hwX3d4MVY5dHFPbFFRIiwidmVyaWZpY2F0aW9uIix7InRydXN0X2ZyYW1ld29yayI6ICJpdF9jaWUiLCJhc3N1cmFuY2VfbGV2ZWwiOiAic3Vic3RhbnRpYWwifV0";
35
+ expect(() => getVerification(`${signed}~${disclosure}`)).toThrow();
36
+ });
37
+ });
@@ -10,6 +10,8 @@ import * as Errors from "./errors";
10
10
  import { Base64 } from "js-base64";
11
11
  import { type Presentation } from "../credential/presentation/types";
12
12
 
13
+ export * from "./utils";
14
+
13
15
  const decodeDisclosure = (encoded: string): DisclosureWithEncoded => {
14
16
  const utf8String = Base64.decode(encoded); // Decode Base64 into UTF-8 string
15
17
  const decoded = Disclosure.parse(JSON.parse(utf8String));
@@ -36,7 +36,7 @@ export type DisclosureWithEncoded = {
36
36
  export type SdJwt4VC = z.infer<typeof SdJwt4VC>;
37
37
  export const SdJwt4VC = z.object({
38
38
  header: z.object({
39
- typ: z.literal("vc+sd-jwt"),
39
+ typ: z.literal("dc+sd-jwt"),
40
40
  alg: z.string(),
41
41
  kid: z.string().optional(),
42
42
  }),
@@ -48,7 +48,7 @@ export const SdJwt4VC = z.object({
48
48
  exp: UnixTime,
49
49
  _sd_alg: z.literal("sha-256"),
50
50
  status: z.object({
51
- status_attestation: z.object({
51
+ status_assertion: z.object({
52
52
  credential_hash_alg: z.literal("sha-256"),
53
53
  }),
54
54
  }),
@@ -56,7 +56,54 @@ export const SdJwt4VC = z.object({
56
56
  jwk: JWK,
57
57
  }),
58
58
  vct: z.string(),
59
+ "vct#integrity": z.string(),
60
+ issuing_authority: z.string(),
61
+ issuing_country: z.string(),
59
62
  }),
60
63
  ObfuscatedDisclosures
61
64
  ),
62
65
  });
66
+
67
+ /**
68
+ * Object containing User authentication and User data verification information.
69
+ * Useful to extract the assurance level to determine L2/L3 authentication.
70
+ */
71
+ export type Verification = z.infer<typeof Verification>;
72
+ export const Verification = z.object({
73
+ trust_framework: z.string(),
74
+ assurance_level: z.string(),
75
+ evidence: z.array(
76
+ z.object({
77
+ type: z.literal("vouch"),
78
+ time: z.string(),
79
+ attestation: z.object({
80
+ type: z.literal("digital_attestation"),
81
+ reference_number: z.string(),
82
+ date_of_issuance: z.string(),
83
+ voucher: z.object({ organization: z.string() }),
84
+ }),
85
+ })
86
+ ),
87
+ });
88
+
89
+ /**
90
+ * Metadata for a digital credential. This information is retrieved from the URL defined in the `vct` claim.
91
+ *
92
+ * @see https://italia.github.io/eid-wallet-it-docs/v0.9.1/en/pid-eaa-data-model.html#digital-credential-metadata-type
93
+ */
94
+ export type TypeMetadata = z.infer<typeof TypeMetadata>;
95
+ export const TypeMetadata = z.object({
96
+ name: z.string(),
97
+ description: z.string(),
98
+ data_source: z.object({
99
+ trust_framework: z.string(),
100
+ authentic_source: z.object({
101
+ organization_name: z.string(),
102
+ organization_code: z.string(),
103
+ contacts: z.array(z.string()),
104
+ homepage_uri: z.string().url(),
105
+ logo_uri: z.string().url(),
106
+ }),
107
+ }),
108
+ // TODO: add more fields
109
+ });