@pagopa/io-react-native-wallet 2.0.0-next.1 → 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 (174) hide show
  1. package/lib/commonjs/credential/issuance/02-evaluate-issuer-trust.js +2 -2
  2. package/lib/commonjs/credential/issuance/02-evaluate-issuer-trust.js.map +1 -1
  3. package/lib/commonjs/credential/issuance/03-start-user-authorization.js +38 -24
  4. package/lib/commonjs/credential/issuance/03-start-user-authorization.js.map +1 -1
  5. package/lib/commonjs/credential/issuance/05-authorize-access.js +6 -10
  6. package/lib/commonjs/credential/issuance/05-authorize-access.js.map +1 -1
  7. package/lib/commonjs/credential/issuance/06-obtain-credential.js +43 -11
  8. package/lib/commonjs/credential/issuance/06-obtain-credential.js.map +1 -1
  9. package/lib/commonjs/credential/issuance/07-verify-and-parse-credential.js +51 -48
  10. package/lib/commonjs/credential/issuance/07-verify-and-parse-credential.js.map +1 -1
  11. package/lib/commonjs/credential/issuance/README.md +34 -13
  12. package/lib/commonjs/credential/issuance/const.js +1 -1
  13. package/lib/commonjs/credential/issuance/types.js +16 -10
  14. package/lib/commonjs/credential/issuance/types.js.map +1 -1
  15. package/lib/commonjs/credential/presentation/02-evaluate-rp-trust.js +2 -2
  16. package/lib/commonjs/credential/presentation/02-evaluate-rp-trust.js.map +1 -1
  17. package/lib/commonjs/credential/presentation/05-verify-request-object.js.map +1 -1
  18. package/lib/commonjs/credential/presentation/07-evaluate-dcql-query.js +4 -4
  19. package/lib/commonjs/credential/presentation/07-evaluate-input-descriptor.js +3 -3
  20. package/lib/commonjs/credential/presentation/08-send-authorization-response.js.map +1 -1
  21. package/lib/commonjs/credential/status/README.md +0 -1
  22. package/lib/commonjs/sd-jwt/__test__/index.test.js +11 -15
  23. package/lib/commonjs/sd-jwt/__test__/index.test.js.map +1 -1
  24. package/lib/commonjs/sd-jwt/__test__/types.test.js +5 -2
  25. package/lib/commonjs/sd-jwt/__test__/types.test.js.map +1 -1
  26. package/lib/commonjs/sd-jwt/__test__/utils.test.js +37 -0
  27. package/lib/commonjs/sd-jwt/__test__/utils.test.js.map +1 -0
  28. package/lib/commonjs/sd-jwt/index.js +20 -0
  29. package/lib/commonjs/sd-jwt/index.js.map +1 -1
  30. package/lib/commonjs/sd-jwt/types.js +51 -4
  31. package/lib/commonjs/sd-jwt/types.js.map +1 -1
  32. package/lib/commonjs/sd-jwt/utils.js +64 -0
  33. package/lib/commonjs/sd-jwt/utils.js.map +1 -0
  34. package/lib/commonjs/trust/build-chain.js +252 -0
  35. package/lib/commonjs/trust/build-chain.js.map +1 -0
  36. package/lib/commonjs/trust/index.js +11 -282
  37. package/lib/commonjs/trust/index.js.map +1 -1
  38. package/lib/commonjs/trust/types.js +18 -13
  39. package/lib/commonjs/trust/types.js.map +1 -1
  40. package/lib/commonjs/trust/{chain.js → verify-chain.js} +40 -5
  41. package/lib/commonjs/trust/verify-chain.js.map +1 -0
  42. package/lib/commonjs/utils/errors.js.map +1 -1
  43. package/lib/commonjs/utils/par.js +32 -22
  44. package/lib/commonjs/utils/par.js.map +1 -1
  45. package/lib/commonjs/utils/pop.js +1 -1
  46. package/lib/commonjs/utils/pop.js.map +1 -1
  47. package/lib/commonjs/wallet-instance-attestation/types.js +5 -1
  48. package/lib/commonjs/wallet-instance-attestation/types.js.map +1 -1
  49. package/lib/module/credential/issuance/02-evaluate-issuer-trust.js +1 -1
  50. package/lib/module/credential/issuance/02-evaluate-issuer-trust.js.map +1 -1
  51. package/lib/module/credential/issuance/03-start-user-authorization.js +38 -24
  52. package/lib/module/credential/issuance/03-start-user-authorization.js.map +1 -1
  53. package/lib/module/credential/issuance/05-authorize-access.js +6 -10
  54. package/lib/module/credential/issuance/05-authorize-access.js.map +1 -1
  55. package/lib/module/credential/issuance/06-obtain-credential.js +44 -12
  56. package/lib/module/credential/issuance/06-obtain-credential.js.map +1 -1
  57. package/lib/module/credential/issuance/07-verify-and-parse-credential.js +51 -48
  58. package/lib/module/credential/issuance/07-verify-and-parse-credential.js.map +1 -1
  59. package/lib/module/credential/issuance/README.md +34 -13
  60. package/lib/module/credential/issuance/const.js +1 -1
  61. package/lib/module/credential/issuance/types.js +12 -8
  62. package/lib/module/credential/issuance/types.js.map +1 -1
  63. package/lib/module/credential/presentation/02-evaluate-rp-trust.js +1 -1
  64. package/lib/module/credential/presentation/02-evaluate-rp-trust.js.map +1 -1
  65. package/lib/module/credential/presentation/05-verify-request-object.js.map +1 -1
  66. package/lib/module/credential/presentation/07-evaluate-dcql-query.js +4 -4
  67. package/lib/module/credential/presentation/07-evaluate-input-descriptor.js +3 -3
  68. package/lib/module/credential/presentation/08-send-authorization-response.js +1 -1
  69. package/lib/module/credential/presentation/08-send-authorization-response.js.map +1 -1
  70. package/lib/module/credential/status/README.md +0 -1
  71. package/lib/module/sd-jwt/__test__/index.test.js +11 -16
  72. package/lib/module/sd-jwt/__test__/index.test.js.map +1 -1
  73. package/lib/module/sd-jwt/__test__/types.test.js +5 -2
  74. package/lib/module/sd-jwt/__test__/types.test.js.map +1 -1
  75. package/lib/module/sd-jwt/__test__/utils.test.js +35 -0
  76. package/lib/module/sd-jwt/__test__/utils.test.js.map +1 -0
  77. package/lib/module/sd-jwt/index.js +1 -0
  78. package/lib/module/sd-jwt/index.js.map +1 -1
  79. package/lib/module/sd-jwt/types.js +50 -3
  80. package/lib/module/sd-jwt/types.js.map +1 -1
  81. package/lib/module/sd-jwt/utils.js +57 -0
  82. package/lib/module/sd-jwt/utils.js.map +1 -0
  83. package/lib/module/trust/build-chain.js +235 -0
  84. package/lib/module/trust/build-chain.js.map +1 -0
  85. package/lib/module/trust/index.js +5 -268
  86. package/lib/module/trust/index.js.map +1 -1
  87. package/lib/module/trust/types.js +18 -13
  88. package/lib/module/trust/types.js.map +1 -1
  89. package/lib/module/trust/{chain.js → verify-chain.js} +36 -2
  90. package/lib/module/trust/verify-chain.js.map +1 -0
  91. package/lib/module/utils/errors.js +1 -1
  92. package/lib/module/utils/errors.js.map +1 -1
  93. package/lib/module/utils/par.js +29 -20
  94. package/lib/module/utils/par.js.map +1 -1
  95. package/lib/module/utils/pop.js +1 -1
  96. package/lib/module/utils/pop.js.map +1 -1
  97. package/lib/module/wallet-instance-attestation/types.js +5 -1
  98. package/lib/module/wallet-instance-attestation/types.js.map +1 -1
  99. package/lib/typescript/client/generated/wallet-provider.d.ts +12 -12
  100. package/lib/typescript/credential/issuance/01-start-flow.d.ts +2 -2
  101. package/lib/typescript/credential/issuance/01-start-flow.d.ts.map +1 -1
  102. package/lib/typescript/credential/issuance/02-evaluate-issuer-trust.d.ts.map +1 -1
  103. package/lib/typescript/credential/issuance/03-start-user-authorization.d.ts +7 -6
  104. package/lib/typescript/credential/issuance/03-start-user-authorization.d.ts.map +1 -1
  105. package/lib/typescript/credential/issuance/05-authorize-access.d.ts.map +1 -1
  106. package/lib/typescript/credential/issuance/06-obtain-credential.d.ts +10 -5
  107. package/lib/typescript/credential/issuance/06-obtain-credential.d.ts.map +1 -1
  108. package/lib/typescript/credential/issuance/07-verify-and-parse-credential.d.ts +3 -2
  109. package/lib/typescript/credential/issuance/07-verify-and-parse-credential.d.ts.map +1 -1
  110. package/lib/typescript/credential/issuance/const.d.ts +1 -1
  111. package/lib/typescript/credential/issuance/types.d.ts +46 -26
  112. package/lib/typescript/credential/issuance/types.d.ts.map +1 -1
  113. package/lib/typescript/credential/presentation/02-evaluate-rp-trust.d.ts.map +1 -1
  114. package/lib/typescript/credential/presentation/05-verify-request-object.d.ts +1 -1
  115. package/lib/typescript/credential/presentation/05-verify-request-object.d.ts.map +1 -1
  116. package/lib/typescript/credential/presentation/08-send-authorization-response.d.ts +2 -2
  117. package/lib/typescript/credential/presentation/08-send-authorization-response.d.ts.map +1 -1
  118. package/lib/typescript/credential/presentation/types.d.ts +4 -4
  119. package/lib/typescript/pid/sd-jwt/types.d.ts +7 -7
  120. package/lib/typescript/sd-jwt/__test__/utils.test.d.ts +2 -0
  121. package/lib/typescript/sd-jwt/__test__/utils.test.d.ts.map +1 -0
  122. package/lib/typescript/sd-jwt/index.d.ts +21 -8
  123. package/lib/typescript/sd-jwt/index.d.ts.map +1 -1
  124. package/lib/typescript/sd-jwt/types.d.ts +194 -12
  125. package/lib/typescript/sd-jwt/types.d.ts.map +1 -1
  126. package/lib/typescript/sd-jwt/utils.d.ts +18 -0
  127. package/lib/typescript/sd-jwt/utils.d.ts.map +1 -0
  128. package/lib/typescript/trust/build-chain.d.ts +1300 -0
  129. package/lib/typescript/trust/build-chain.d.ts.map +1 -0
  130. package/lib/typescript/trust/index.d.ts +5 -1301
  131. package/lib/typescript/trust/index.d.ts.map +1 -1
  132. package/lib/typescript/trust/types.d.ts +788 -624
  133. package/lib/typescript/trust/types.d.ts.map +1 -1
  134. package/lib/typescript/trust/{chain.d.ts → verify-chain.d.ts} +17 -1
  135. package/lib/typescript/trust/verify-chain.d.ts.map +1 -0
  136. package/lib/typescript/utils/errors.d.ts +2 -2
  137. package/lib/typescript/utils/errors.d.ts.map +1 -1
  138. package/lib/typescript/utils/par.d.ts +29 -13
  139. package/lib/typescript/utils/par.d.ts.map +1 -1
  140. package/lib/typescript/wallet-instance-attestation/types.d.ts +9 -9
  141. package/lib/typescript/wallet-instance-attestation/types.d.ts.map +1 -1
  142. package/package.json +1 -1
  143. package/src/credential/issuance/01-start-flow.ts +2 -2
  144. package/src/credential/issuance/02-evaluate-issuer-trust.ts +1 -1
  145. package/src/credential/issuance/03-start-user-authorization.ts +57 -38
  146. package/src/credential/issuance/05-authorize-access.ts +5 -11
  147. package/src/credential/issuance/06-obtain-credential.ts +53 -23
  148. package/src/credential/issuance/07-verify-and-parse-credential.ts +54 -62
  149. package/src/credential/issuance/README.md +34 -13
  150. package/src/credential/issuance/const.ts +1 -1
  151. package/src/credential/issuance/types.ts +18 -8
  152. package/src/credential/presentation/02-evaluate-rp-trust.ts +1 -1
  153. package/src/credential/presentation/05-verify-request-object.ts +1 -1
  154. package/src/credential/presentation/07-evaluate-dcql-query.ts +4 -4
  155. package/src/credential/presentation/07-evaluate-input-descriptor.ts +3 -3
  156. package/src/credential/presentation/08-send-authorization-response.ts +4 -4
  157. package/src/credential/status/README.md +0 -1
  158. package/src/sd-jwt/__test__/index.test.ts +8 -29
  159. package/src/sd-jwt/__test__/types.test.ts +6 -2
  160. package/src/sd-jwt/__test__/utils.test.ts +37 -0
  161. package/src/sd-jwt/index.ts +2 -0
  162. package/src/sd-jwt/types.ts +49 -2
  163. package/src/sd-jwt/utils.ts +73 -0
  164. package/src/trust/build-chain.ts +395 -0
  165. package/src/trust/index.ts +5 -442
  166. package/src/trust/types.ts +23 -17
  167. package/src/trust/{chain.ts → verify-chain.ts} +41 -1
  168. package/src/utils/errors.ts +4 -4
  169. package/src/utils/par.ts +37 -21
  170. package/src/utils/pop.ts +1 -1
  171. package/src/wallet-instance-attestation/types.ts +3 -1
  172. package/lib/commonjs/trust/chain.js.map +0 -1
  173. package/lib/module/trust/chain.js.map +0 -1
  174. package/lib/typescript/trust/chain.d.ts.map +0 -1
@@ -14,7 +14,7 @@ import {
14
14
  UnexpectedStatusCodeError,
15
15
  ValidationFailed,
16
16
  } from "../../utils/errors";
17
- import { CredentialResponse } from "./types";
17
+ import { CredentialResponse, NonceResponse } from "./types";
18
18
  import { createDPopToken } from "../../utils/dpop";
19
19
  import { v4 as uuidv4 } from "uuid";
20
20
  import { LogLevel, Logger } from "../../utils/logging";
@@ -23,14 +23,17 @@ export type ObtainCredential = (
23
23
  issuerConf: Out<EvaluateIssuerTrust>["issuerConf"],
24
24
  accessToken: Out<AuthorizeAccess>["accessToken"],
25
25
  clientId: Out<StartUserAuthorization>["clientId"],
26
- credentialDefinition: Out<StartUserAuthorization>["credentialDefinition"],
26
+ credentialDefinition: {
27
+ credential_configuration_id: string;
28
+ credential_identifier?: string;
29
+ },
27
30
  context: {
28
31
  dPopCryptoContext: CryptoContext;
29
32
  credentialCryptoContext: CryptoContext;
30
33
  appFetch?: GlobalFetch["fetch"];
31
34
  },
32
35
  operationType?: "reissuing"
33
- ) => Promise<CredentialResponse>;
36
+ ) => Promise<{ credential: string; format: string }>;
34
37
 
35
38
  export const createNonceProof = async (
36
39
  nonce: string,
@@ -63,11 +66,11 @@ export const createNonceProof = async (
63
66
  * @param issuerConf The issuer configuration returned by {@link evaluateIssuerTrust}
64
67
  * @param accessToken The access token response returned by {@link authorizeAccess}
65
68
  * @param clientId The client id returned by {@link startUserAuthorization}
66
- * @param credentialDefinition The credential definition of the credential to be obtained returned by {@link startUserAuthorization}
67
- * @param tokenRequestSignedDPop The DPoP signed token request returned by {@link authorizeAccess}
69
+ * @param credentialDefinition The credential definition of the credential to be obtained returned by {@link authorizeAccess}
68
70
  * @param context.credentialCryptoContext The crypto context used to obtain the credential
69
71
  * @param context.dPopCryptoContext The DPoP crypto context
70
72
  * @param context.appFetch (optional) fetch api implementation. Default: built-in fetch
73
+ * @param operationType Specify the type of credential issuance (used for reissuing)
71
74
  * @returns The credential response containing the credential
72
75
  */
73
76
  export const obtainCredential: ObtainCredential = async (
@@ -83,8 +86,21 @@ export const obtainCredential: ObtainCredential = async (
83
86
  appFetch = fetch,
84
87
  dPopCryptoContext,
85
88
  } = context;
89
+ const { credential_configuration_id, credential_identifier } =
90
+ credentialDefinition;
86
91
 
87
92
  const credentialUrl = issuerConf.openid_credential_issuer.credential_endpoint;
93
+ const issuerUrl = issuerConf.oauth_authorization_server.issuer;
94
+ const nonceUrl = issuerConf.openid_credential_issuer.nonce_endpoint;
95
+
96
+ // Fetch the nonce from the Credential Issuer
97
+ const { c_nonce } = await appFetch(nonceUrl, {
98
+ method: "POST",
99
+ headers: { "Content-Type": "application/json" },
100
+ })
101
+ .then(hasStatusOrThrow(200))
102
+ .then((res) => res.json())
103
+ .then((body) => NonceResponse.parse(body));
88
104
 
89
105
  /**
90
106
  * JWT proof token to bind the request nonce to the key that will bind the holder User with the Credential
@@ -92,9 +108,9 @@ export const obtainCredential: ObtainCredential = async (
92
108
  * @see https://openid.net/specs/openid-4-verifiable-credential-issuance-1_0.html#name-proof-types
93
109
  */
94
110
  const signedNonceProof = await createNonceProof(
95
- accessToken.c_nonce,
111
+ c_nonce,
96
112
  clientId,
97
- credentialUrl,
113
+ issuerUrl,
98
114
  credentialCryptoContext
99
115
  );
100
116
 
@@ -103,10 +119,10 @@ export const obtainCredential: ObtainCredential = async (
103
119
  // Validation of accessTokenResponse.authorization_details if contain credentialDefinition
104
120
  const containsCredentialDefinition = accessToken.authorization_details.some(
105
121
  (c) =>
106
- c.credential_configuration_id ===
107
- credentialDefinition.credential_configuration_id &&
108
- c.format === credentialDefinition.format &&
109
- c.type === credentialDefinition.type
122
+ c.credential_configuration_id === credential_configuration_id &&
123
+ (credential_identifier
124
+ ? c.credential_identifiers.includes(credential_identifier)
125
+ : true)
110
126
  );
111
127
 
112
128
  if (!containsCredentialDefinition) {
@@ -120,17 +136,21 @@ export const obtainCredential: ObtainCredential = async (
120
136
  });
121
137
  }
122
138
 
123
- /** The credential request body */
124
- const credentialRequestFormBody = {
125
- credential_definition: {
126
- type: [credentialDefinition.credential_configuration_id],
127
- },
128
- format: credentialDefinition.format,
129
- proof: {
130
- jwt: signedNonceProof,
131
- proof_type: "jwt",
132
- },
133
- };
139
+ /**
140
+ * The credential request body.
141
+ * We accept both `credential_identifier` (recommended) and `credential_configuration_id`
142
+ * when the Authorization Server does not support `credential_identifier`.
143
+ * @see https://openid.net/specs/openid-4-verifiable-credential-issuance-1_0-15.html#section-3.3.4
144
+ */
145
+ const credentialRequestFormBody = credential_identifier
146
+ ? {
147
+ credential_identifier: credential_identifier,
148
+ proof: { jwt: signedNonceProof, proof_type: "jwt" },
149
+ }
150
+ : {
151
+ credential_configuration_id: credential_configuration_id,
152
+ proof: { jwt: signedNonceProof, proof_type: "jwt" },
153
+ };
134
154
 
135
155
  Logger.log(
136
156
  LogLevel.DEBUG,
@@ -180,7 +200,17 @@ export const obtainCredential: ObtainCredential = async (
180
200
  `Credential Response: ${JSON.stringify(credentialRes.data)}`
181
201
  );
182
202
 
183
- return credentialRes.data;
203
+ // Extract the format corresponding to the credential_configuration_id used
204
+ const issuerCredentialConfig =
205
+ issuerConf.openid_credential_issuer.credential_configurations_supported[
206
+ credential_configuration_id
207
+ ];
208
+
209
+ // TODO: [SIW-2264] Handle multiple credentials
210
+ return {
211
+ credential: credentialRes.data.credentials.at(0)!.credential,
212
+ format: issuerCredentialConfig!.format,
213
+ };
184
214
  };
185
215
 
186
216
  /**
@@ -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
+ });
@@ -1,7 +1,7 @@
1
- import { getRelyingPartyEntityConfiguration } from "../../trust";
2
1
  import { RelyingPartyEntityConfiguration } from "../../trust/types";
3
2
  import type { StartFlow } from "../issuance/01-start-flow";
4
3
  import type { Out } from "../../utils/misc";
4
+ import { getRelyingPartyEntityConfiguration } from "../../trust/build-chain";
5
5
 
6
6
  export type EvaluateRelyingPartyTrust = (
7
7
  rpUrl: Out<StartFlow>["issuerUrl"],
@@ -1,8 +1,8 @@
1
1
  import { decode as decodeJwt, verify } from "@pagopa/io-react-native-jwt";
2
- import type { RelyingPartyEntityConfiguration } from "../../trust";
3
2
  import { InvalidRequestObjectError } from "./errors";
4
3
  import { RequestObject } from "./types";
5
4
  import { getJwksFromConfig } from "./04-retrieve-rp-jwks";
5
+ import type { RelyingPartyEntityConfiguration } from "../../trust/types";
6
6
 
7
7
  export type VerifyRequestObject = (
8
8
  requestObjectEncodedJwt: string,
@@ -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
 
@@ -1,24 +1,24 @@
1
1
  import { EncryptJwe } from "@pagopa/io-react-native-jwt";
2
2
  import uuid from "react-native-uuid";
3
- import { getJwksFromConfig, type FetchJwks } from "./04-retrieve-rp-jwks";
3
+ import { type FetchJwks, getJwksFromConfig } from "./04-retrieve-rp-jwks";
4
4
  import type { VerifyRequestObject } from "./05-verify-request-object";
5
5
  import { NoSuitableKeysFoundInEntityConfiguration } from "./errors";
6
6
  import { hasStatusOrThrow, type Out } from "../../utils/misc";
7
7
  import {
8
- type RemotePresentation,
9
8
  DirectAuthorizationBodyPayload,
10
9
  ErrorResponse,
11
10
  type LegacyRemotePresentation,
11
+ type RemotePresentation,
12
12
  } from "./types";
13
13
  import * as z from "zod";
14
14
  import type { JWK } from "../../utils/jwk";
15
- import type { RelyingPartyEntityConfiguration } from "../../trust";
16
15
  import {
17
16
  RelyingPartyResponseError,
17
+ RelyingPartyResponseErrorCodes,
18
18
  ResponseErrorBuilder,
19
19
  UnexpectedStatusCodeError,
20
- RelyingPartyResponseErrorCodes,
21
20
  } from "../../utils/errors";
21
+ import type { RelyingPartyEntityConfiguration } from "../../trust/types";
22
22
 
23
23
  export type AuthorizationResponse = z.infer<typeof AuthorizationResponse>;
24
24
  export const AuthorizationResponse = z.object({
@@ -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