@pagopa/io-react-native-wallet 3.1.1 → 3.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (174) hide show
  1. package/lib/commonjs/credential/issuance/README.md +44 -17
  2. package/lib/commonjs/credential/issuance/v1.0.0/03-complete-user-authorization.js +5 -2
  3. package/lib/commonjs/credential/issuance/v1.0.0/03-complete-user-authorization.js.map +1 -1
  4. package/lib/commonjs/credential/issuance/v1.0.0/05-obtain-credential.js +5 -1
  5. package/lib/commonjs/credential/issuance/v1.0.0/05-obtain-credential.js.map +1 -1
  6. package/lib/commonjs/credential/issuance/v1.0.0/index.js +1 -0
  7. package/lib/commonjs/credential/issuance/v1.0.0/index.js.map +1 -1
  8. package/lib/commonjs/credential/issuance/v1.3.3/03-complete-user-authorization.js +1 -1
  9. package/lib/commonjs/credential/issuance/v1.3.3/03-complete-user-authorization.js.map +1 -1
  10. package/lib/commonjs/credential/issuance/v1.3.3/05-obtain-credential.js +147 -52
  11. package/lib/commonjs/credential/issuance/v1.3.3/05-obtain-credential.js.map +1 -1
  12. package/lib/commonjs/credential/issuance/v1.3.3/index.js +1 -0
  13. package/lib/commonjs/credential/issuance/v1.3.3/index.js.map +1 -1
  14. package/lib/commonjs/credential/presentation/api/types.js.map +1 -1
  15. package/lib/commonjs/credential/presentation/v1.0.0/05-verify-request-object.js +18 -12
  16. package/lib/commonjs/credential/presentation/v1.0.0/05-verify-request-object.js.map +1 -1
  17. package/lib/commonjs/credential/presentation/v1.0.0/07-send-authorization-response.js +3 -0
  18. package/lib/commonjs/credential/presentation/v1.0.0/07-send-authorization-response.js.map +1 -1
  19. package/lib/commonjs/credential/presentation/v1.0.0/index.js +0 -2
  20. package/lib/commonjs/credential/presentation/v1.0.0/index.js.map +1 -1
  21. package/lib/commonjs/credential/presentation/v1.0.0/mappers.js +23 -13
  22. package/lib/commonjs/credential/presentation/v1.0.0/mappers.js.map +1 -1
  23. package/lib/commonjs/credential/presentation/v1.0.0/types.js +25 -17
  24. package/lib/commonjs/credential/presentation/v1.0.0/types.js.map +1 -1
  25. package/lib/commonjs/credential/presentation/v1.3.3/05-verify-request-object.js +29 -6
  26. package/lib/commonjs/credential/presentation/v1.3.3/05-verify-request-object.js.map +1 -1
  27. package/lib/commonjs/credential/presentation/v1.3.3/07-send-authorization-response.js +9 -6
  28. package/lib/commonjs/credential/presentation/v1.3.3/07-send-authorization-response.js.map +1 -1
  29. package/lib/commonjs/credential/presentation/v1.3.3/mappers.js +25 -13
  30. package/lib/commonjs/credential/presentation/v1.3.3/mappers.js.map +1 -1
  31. package/lib/commonjs/credential/presentation/v1.3.3/types.js +6 -3
  32. package/lib/commonjs/credential/presentation/v1.3.3/types.js.map +1 -1
  33. package/lib/commonjs/credentials-catalogue/api/DigitalCredentialsCatalogue.js +26 -1
  34. package/lib/commonjs/credentials-catalogue/api/DigitalCredentialsCatalogue.js.map +1 -1
  35. package/lib/commonjs/credentials-catalogue/v1.3.3/fetch-and-parse-catalogue.js +4 -0
  36. package/lib/commonjs/credentials-catalogue/v1.3.3/fetch-and-parse-catalogue.js.map +1 -1
  37. package/lib/commonjs/credentials-catalogue/v1.3.3/fetch-translations.js +5 -3
  38. package/lib/commonjs/credentials-catalogue/v1.3.3/fetch-translations.js.map +1 -1
  39. package/lib/commonjs/credentials-catalogue/v1.3.3/mappers.js +9 -1
  40. package/lib/commonjs/credentials-catalogue/v1.3.3/mappers.js.map +1 -1
  41. package/lib/commonjs/credentials-catalogue/v1.3.3/types.js +49 -1
  42. package/lib/commonjs/credentials-catalogue/v1.3.3/types.js.map +1 -1
  43. package/lib/commonjs/utils/callbacks.js +25 -6
  44. package/lib/commonjs/utils/callbacks.js.map +1 -1
  45. package/lib/commonjs/utils/crypto.js +58 -5
  46. package/lib/commonjs/utils/crypto.js.map +1 -1
  47. package/lib/module/credential/issuance/README.md +44 -17
  48. package/lib/module/credential/issuance/v1.0.0/03-complete-user-authorization.js +6 -3
  49. package/lib/module/credential/issuance/v1.0.0/03-complete-user-authorization.js.map +1 -1
  50. package/lib/module/credential/issuance/v1.0.0/05-obtain-credential.js +4 -1
  51. package/lib/module/credential/issuance/v1.0.0/05-obtain-credential.js.map +1 -1
  52. package/lib/module/credential/issuance/v1.0.0/index.js +2 -1
  53. package/lib/module/credential/issuance/v1.0.0/index.js.map +1 -1
  54. package/lib/module/credential/issuance/v1.3.3/03-complete-user-authorization.js +1 -1
  55. package/lib/module/credential/issuance/v1.3.3/03-complete-user-authorization.js.map +1 -1
  56. package/lib/module/credential/issuance/v1.3.3/05-obtain-credential.js +143 -49
  57. package/lib/module/credential/issuance/v1.3.3/05-obtain-credential.js.map +1 -1
  58. package/lib/module/credential/issuance/v1.3.3/index.js +2 -1
  59. package/lib/module/credential/issuance/v1.3.3/index.js.map +1 -1
  60. package/lib/module/credential/presentation/api/types.js.map +1 -1
  61. package/lib/module/credential/presentation/v1.0.0/05-verify-request-object.js +13 -7
  62. package/lib/module/credential/presentation/v1.0.0/05-verify-request-object.js.map +1 -1
  63. package/lib/module/credential/presentation/v1.0.0/07-send-authorization-response.js +4 -1
  64. package/lib/module/credential/presentation/v1.0.0/07-send-authorization-response.js.map +1 -1
  65. package/lib/module/credential/presentation/v1.0.0/index.js +0 -2
  66. package/lib/module/credential/presentation/v1.0.0/index.js.map +1 -1
  67. package/lib/module/credential/presentation/v1.0.0/mappers.js +23 -13
  68. package/lib/module/credential/presentation/v1.0.0/mappers.js.map +1 -1
  69. package/lib/module/credential/presentation/v1.0.0/types.js +23 -15
  70. package/lib/module/credential/presentation/v1.0.0/types.js.map +1 -1
  71. package/lib/module/credential/presentation/v1.3.3/05-verify-request-object.js +28 -6
  72. package/lib/module/credential/presentation/v1.3.3/05-verify-request-object.js.map +1 -1
  73. package/lib/module/credential/presentation/v1.3.3/07-send-authorization-response.js +9 -6
  74. package/lib/module/credential/presentation/v1.3.3/07-send-authorization-response.js.map +1 -1
  75. package/lib/module/credential/presentation/v1.3.3/mappers.js +25 -13
  76. package/lib/module/credential/presentation/v1.3.3/mappers.js.map +1 -1
  77. package/lib/module/credential/presentation/v1.3.3/types.js +5 -2
  78. package/lib/module/credential/presentation/v1.3.3/types.js.map +1 -1
  79. package/lib/module/credentials-catalogue/api/DigitalCredentialsCatalogue.js +24 -0
  80. package/lib/module/credentials-catalogue/api/DigitalCredentialsCatalogue.js.map +1 -1
  81. package/lib/module/credentials-catalogue/v1.3.3/fetch-and-parse-catalogue.js +5 -1
  82. package/lib/module/credentials-catalogue/v1.3.3/fetch-and-parse-catalogue.js.map +1 -1
  83. package/lib/module/credentials-catalogue/v1.3.3/fetch-translations.js +5 -3
  84. package/lib/module/credentials-catalogue/v1.3.3/fetch-translations.js.map +1 -1
  85. package/lib/module/credentials-catalogue/v1.3.3/mappers.js +9 -1
  86. package/lib/module/credentials-catalogue/v1.3.3/mappers.js.map +1 -1
  87. package/lib/module/credentials-catalogue/v1.3.3/types.js +47 -0
  88. package/lib/module/credentials-catalogue/v1.3.3/types.js.map +1 -1
  89. package/lib/module/utils/callbacks.js +26 -7
  90. package/lib/module/utils/callbacks.js.map +1 -1
  91. package/lib/module/utils/crypto.js +57 -6
  92. package/lib/module/utils/crypto.js.map +1 -1
  93. package/lib/typescript/credential/issuance/api/05-obtain-credential.d.ts +20 -0
  94. package/lib/typescript/credential/issuance/api/05-obtain-credential.d.ts.map +1 -1
  95. package/lib/typescript/credential/issuance/v1.0.0/03-complete-user-authorization.d.ts.map +1 -1
  96. package/lib/typescript/credential/issuance/v1.0.0/05-obtain-credential.d.ts +1 -0
  97. package/lib/typescript/credential/issuance/v1.0.0/05-obtain-credential.d.ts.map +1 -1
  98. package/lib/typescript/credential/issuance/v1.0.0/index.d.ts.map +1 -1
  99. package/lib/typescript/credential/issuance/v1.3.3/05-obtain-credential.d.ts +23 -2
  100. package/lib/typescript/credential/issuance/v1.3.3/05-obtain-credential.d.ts.map +1 -1
  101. package/lib/typescript/credential/issuance/v1.3.3/index.d.ts.map +1 -1
  102. package/lib/typescript/credential/presentation/api/04-verify-certificate-chain.d.ts +9 -2
  103. package/lib/typescript/credential/presentation/api/04-verify-certificate-chain.d.ts.map +1 -1
  104. package/lib/typescript/credential/presentation/api/05-verify-request-object.d.ts +2 -2
  105. package/lib/typescript/credential/presentation/api/05-verify-request-object.d.ts.map +1 -1
  106. package/lib/typescript/credential/presentation/api/07-send-authorization-response.d.ts +2 -2
  107. package/lib/typescript/credential/presentation/api/07-send-authorization-response.d.ts.map +1 -1
  108. package/lib/typescript/credential/presentation/api/types.d.ts +18 -0
  109. package/lib/typescript/credential/presentation/api/types.d.ts.map +1 -1
  110. package/lib/typescript/credential/presentation/v1.0.0/05-verify-request-object.d.ts.map +1 -1
  111. package/lib/typescript/credential/presentation/v1.0.0/07-send-authorization-response.d.ts.map +1 -1
  112. package/lib/typescript/credential/presentation/v1.0.0/index.d.ts.map +1 -1
  113. package/lib/typescript/credential/presentation/v1.0.0/mappers.d.ts +21 -13
  114. package/lib/typescript/credential/presentation/v1.0.0/mappers.d.ts.map +1 -1
  115. package/lib/typescript/credential/presentation/v1.0.0/types.d.ts +23 -15
  116. package/lib/typescript/credential/presentation/v1.0.0/types.d.ts.map +1 -1
  117. package/lib/typescript/credential/presentation/v1.3.3/05-verify-request-object.d.ts.map +1 -1
  118. package/lib/typescript/credential/presentation/v1.3.3/07-send-authorization-response.d.ts.map +1 -1
  119. package/lib/typescript/credential/presentation/v1.3.3/mappers.d.ts +89 -79
  120. package/lib/typescript/credential/presentation/v1.3.3/mappers.d.ts.map +1 -1
  121. package/lib/typescript/credential/presentation/v1.3.3/types.d.ts +87 -79
  122. package/lib/typescript/credential/presentation/v1.3.3/types.d.ts.map +1 -1
  123. package/lib/typescript/credentials-catalogue/api/DigitalCredentialsCatalogue.d.ts +73 -0
  124. package/lib/typescript/credentials-catalogue/api/DigitalCredentialsCatalogue.d.ts.map +1 -1
  125. package/lib/typescript/credentials-catalogue/api/index.d.ts +6 -5
  126. package/lib/typescript/credentials-catalogue/api/index.d.ts.map +1 -1
  127. package/lib/typescript/credentials-catalogue/v1.0.0/mappers.d.ts +25 -0
  128. package/lib/typescript/credentials-catalogue/v1.0.0/mappers.d.ts.map +1 -1
  129. package/lib/typescript/credentials-catalogue/v1.3.3/fetch-and-parse-catalogue.d.ts.map +1 -1
  130. package/lib/typescript/credentials-catalogue/v1.3.3/fetch-translations.d.ts.map +1 -1
  131. package/lib/typescript/credentials-catalogue/v1.3.3/mappers.d.ts +51 -0
  132. package/lib/typescript/credentials-catalogue/v1.3.3/mappers.d.ts.map +1 -1
  133. package/lib/typescript/credentials-catalogue/v1.3.3/types.d.ts +33 -0
  134. package/lib/typescript/credentials-catalogue/v1.3.3/types.d.ts.map +1 -1
  135. package/lib/typescript/utils/callbacks.d.ts.map +1 -1
  136. package/lib/typescript/utils/crypto.d.ts +32 -15
  137. package/lib/typescript/utils/crypto.d.ts.map +1 -1
  138. package/package.json +2 -1
  139. package/src/credential/issuance/README.md +44 -17
  140. package/src/credential/issuance/api/05-obtain-credential.ts +24 -0
  141. package/src/credential/issuance/v1.0.0/03-complete-user-authorization.ts +8 -3
  142. package/src/credential/issuance/v1.0.0/05-obtain-credential.ts +6 -0
  143. package/src/credential/issuance/v1.0.0/index.ts +5 -1
  144. package/src/credential/issuance/v1.3.3/03-complete-user-authorization.ts +1 -1
  145. package/src/credential/issuance/v1.3.3/05-obtain-credential.ts +175 -80
  146. package/src/credential/issuance/v1.3.3/index.ts +5 -1
  147. package/src/credential/presentation/api/04-verify-certificate-chain.ts +9 -2
  148. package/src/credential/presentation/api/05-verify-request-object.ts +2 -2
  149. package/src/credential/presentation/api/07-send-authorization-response.ts +2 -2
  150. package/src/credential/presentation/api/types.ts +16 -0
  151. package/src/credential/presentation/v1.0.0/05-verify-request-object.ts +21 -10
  152. package/src/credential/presentation/v1.0.0/07-send-authorization-response.ts +7 -0
  153. package/src/credential/presentation/v1.0.0/index.ts +0 -2
  154. package/src/credential/presentation/v1.0.0/mappers.ts +17 -17
  155. package/src/credential/presentation/v1.0.0/types.ts +23 -15
  156. package/src/credential/presentation/v1.3.3/05-verify-request-object.ts +63 -10
  157. package/src/credential/presentation/v1.3.3/07-send-authorization-response.ts +13 -4
  158. package/src/credential/presentation/v1.3.3/mappers.ts +19 -17
  159. package/src/credential/presentation/v1.3.3/types.ts +9 -3
  160. package/src/credentials-catalogue/api/DigitalCredentialsCatalogue.ts +32 -0
  161. package/src/credentials-catalogue/api/index.ts +6 -3
  162. package/src/credentials-catalogue/v1.3.3/fetch-and-parse-catalogue.ts +6 -0
  163. package/src/credentials-catalogue/v1.3.3/fetch-translations.ts +6 -3
  164. package/src/credentials-catalogue/v1.3.3/mappers.ts +17 -1
  165. package/src/credentials-catalogue/v1.3.3/types.ts +51 -0
  166. package/src/utils/callbacks.ts +29 -8
  167. package/src/utils/crypto.ts +86 -15
  168. package/lib/commonjs/credential/presentation/v1.0.0/04-verify-certificate-chain.js +0 -12
  169. package/lib/commonjs/credential/presentation/v1.0.0/04-verify-certificate-chain.js.map +0 -1
  170. package/lib/module/credential/presentation/v1.0.0/04-verify-certificate-chain.js +0 -5
  171. package/lib/module/credential/presentation/v1.0.0/04-verify-certificate-chain.js.map +0 -1
  172. package/lib/typescript/credential/presentation/v1.0.0/04-verify-certificate-chain.d.ts +0 -3
  173. package/lib/typescript/credential/presentation/v1.0.0/04-verify-certificate-chain.d.ts.map +0 -1
  174. package/src/credential/presentation/v1.0.0/04-verify-certificate-chain.ts +0 -10
@@ -1,11 +1,15 @@
1
1
  import { type CryptoContext, SignJWT } from "@pagopa/io-react-native-jwt";
2
- import { createTokenDPoP } from "@pagopa/io-wallet-oauth2";
2
+ import {
3
+ createTokenDPoP,
4
+ type CallbackContext,
5
+ type JwtSignerJwk,
6
+ } from "@pagopa/io-wallet-oauth2";
3
7
  import {
4
8
  fetchCredentialResponse,
5
9
  createCredentialRequest,
6
10
  } from "@pagopa/io-wallet-oid4vci";
7
11
  import { UnexpectedStatusCodeError as SdkUnexpectedStatusCodeError } from "@pagopa/io-wallet-utils";
8
- import { hasStatusOrThrow } from "../../../utils/misc";
12
+ import { hasStatusOrThrow, type Out } from "../../../utils/misc";
9
13
  import {
10
14
  IoWalletError,
11
15
  IssuerResponseError,
@@ -16,108 +20,99 @@ import {
16
20
  import { LogLevel, Logger } from "../../../utils/logging";
17
21
  import { sdkConfigV1_3 } from "../../../utils/config";
18
22
  import { partialCallbacks } from "../../../utils/callbacks";
19
- import type { IssuanceApi } from "../api";
23
+ import type { IssuanceApi, IssuerConfig } from "../api";
20
24
  import { NonceResponse } from "./types";
25
+ import type { AuthorizeAccessApi } from "../api/04-authorize-access";
21
26
 
22
- export const createNonceProof = async (
23
- nonce: string,
24
- issuer: string,
25
- audience: string,
26
- ctx: CryptoContext
27
- ): Promise<string> => {
28
- const jwk = await ctx.getPublicKey();
29
- return new SignJWT(ctx)
30
- .setPayload({
31
- nonce,
32
- })
33
- .setProtectedHeader({
34
- typ: "openid4vci-proof+jwt",
35
- jwk,
36
- })
37
- .setAudience(audience)
38
- .setIssuer(issuer)
39
- .setIssuedAt()
40
- .setExpirationTime("5min")
41
- .sign();
27
+ type CreateRequestParams = {
28
+ clientId: string;
29
+ credentialIdentifier: string;
30
+ accessToken: Out<AuthorizeAccessApi["authorizeAccess"]>["accessToken"];
31
+ issuerConf: IssuerConfig;
32
+ dPopCryptoContext: CryptoContext;
33
+ credentialCryptoContexts: CryptoContext[];
34
+ keyAttestationJwt: string;
35
+ appFetch?: GlobalFetch["fetch"];
42
36
  };
43
37
 
44
- export const obtainCredential: IssuanceApi["obtainCredential"] = async (
38
+ /**
39
+ * Helper to create a credential request and fetch it from the issuer.
40
+ *
41
+ * When multiple keys are provided as {@link CryptoContext}, a batch is requested.
42
+ *
43
+ * @returns The raw credential response
44
+ */
45
+ export const requestCredentials = async ({
45
46
  issuerConf,
46
47
  accessToken,
48
+ credentialIdentifier,
47
49
  clientId,
48
- credentialDefinition,
49
- context
50
- ) => {
51
- const {
52
- credentialCryptoContext,
53
- dPopCryptoContext,
54
- walletUnitAttestation,
55
- appFetch = fetch,
56
- } = context;
57
- if (!walletUnitAttestation) {
58
- throw new ValidationFailed({
59
- message:
60
- "The Wallet Unit Attestation is required to obtain the credential",
61
- });
62
- }
63
-
64
- const { credential_configuration_id, credential_identifier } =
65
- credentialDefinition;
66
-
67
- // Fetch the nonce from the Credential Issuer
50
+ keyAttestationJwt,
51
+ credentialCryptoContexts,
52
+ dPopCryptoContext,
53
+ appFetch = fetch,
54
+ }: CreateRequestParams) => {
68
55
  const { c_nonce } = await appFetch(issuerConf.nonce_endpoint, {
69
56
  method: "POST",
70
57
  headers: { "Content-Type": "application/json" },
71
58
  })
72
59
  .then(hasStatusOrThrow(200))
73
60
  .then((res) => res.json())
74
- .then((body) => NonceResponse.parse(body));
61
+ .then(NonceResponse.parse);
75
62
 
76
- // Validation of accessTokenResponse.authorization_details if contain credentialDefinition
77
- const containsCredentialDefinition = accessToken.authorization_details.some(
78
- (c) =>
79
- c.credential_configuration_id === credential_configuration_id &&
80
- (credential_identifier
81
- ? c.credential_identifiers.includes(credential_identifier)
82
- : true)
63
+ const keys = await Promise.all(
64
+ credentialCryptoContexts.map(async (ctx) => {
65
+ const publicJwk = await ctx.getPublicKey();
66
+ return { publicJwk, cryptoContext: ctx };
67
+ })
83
68
  );
84
69
 
85
- if (!containsCredentialDefinition) {
86
- Logger.log(
87
- LogLevel.ERROR,
88
- `Credential definition not found in the access token response ${accessToken.authorization_details}`
89
- );
90
- throw new ValidationFailed({
91
- message:
92
- "The access token response does not contain the requested credential",
93
- });
94
- }
70
+ const signJwt: CallbackContext["signJwt"] = async (
71
+ jwtSigner,
72
+ { header, payload }
73
+ ) => {
74
+ if (jwtSigner.method !== "jwk") {
75
+ throw new IoWalletError(`Unsupported signer method: ${jwtSigner.method}`);
76
+ }
77
+
78
+ const { cryptoContext } =
79
+ keys.find(({ publicJwk }) => publicJwk.kid === jwtSigner.publicJwk.kid) ??
80
+ {};
81
+
82
+ if (!cryptoContext) {
83
+ throw new IoWalletError(
84
+ `Could not find CryptoContext for key ${jwtSigner.publicJwk.kid}`
85
+ );
86
+ }
87
+
88
+ return {
89
+ jwt: await new SignJWT(cryptoContext)
90
+ .setProtectedHeader(header)
91
+ .setPayload(payload)
92
+ .sign(),
93
+ signerJwk: jwtSigner.publicJwk,
94
+ };
95
+ };
95
96
 
96
- const signerJwk = await credentialCryptoContext.getPublicKey();
97
+ const signers = keys.map<JwtSignerJwk>(({ publicJwk }) => ({
98
+ alg: "ES256",
99
+ method: "jwk",
100
+ publicJwk,
101
+ }));
97
102
 
98
103
  const credentialRequest = await createCredentialRequest({
99
104
  config: sdkConfigV1_3,
100
105
  callbacks: {
101
106
  hash: partialCallbacks.hash,
102
- signJwt: async (_, payload) => ({
103
- jwt: await new SignJWT(credentialCryptoContext)
104
- .setPayload(payload)
105
- .sign(),
106
- signerJwk,
107
- }),
107
+ signJwt,
108
108
  },
109
109
  clientId,
110
- credential_identifier: credentialDefinition.credential_identifier!,
110
+ credential_identifier: credentialIdentifier,
111
111
  issuerIdentifier: issuerConf.credential_issuer,
112
+ maxBatchSize: issuerConf.credential_issuance_batch_size,
112
113
  nonce: c_nonce,
113
- keyAttestation: walletUnitAttestation,
114
- signers: [
115
- {
116
- alg: "ES256",
117
- method: "jwk",
118
- publicJwk: signerJwk,
119
- },
120
- ],
114
+ keyAttestation: keyAttestationJwt,
115
+ signers,
121
116
  });
122
117
 
123
118
  const dPopSignerJwk = await dPopCryptoContext.getPublicKey();
@@ -127,7 +122,7 @@ export const obtainCredential: IssuanceApi["obtainCredential"] = async (
127
122
  ...partialCallbacks,
128
123
  signJwt: async (_, payload) => ({
129
124
  jwt: await new SignJWT(dPopCryptoContext).setPayload(payload).sign(),
130
- signerJwk,
125
+ signerJwk: dPopSignerJwk,
131
126
  }),
132
127
  },
133
128
  signer: {
@@ -142,7 +137,7 @@ export const obtainCredential: IssuanceApi["obtainCredential"] = async (
142
137
  accessToken: accessToken.access_token,
143
138
  });
144
139
 
145
- const credentialRes = await fetchCredentialResponse({
140
+ return await fetchCredentialResponse({
146
141
  callbacks: {
147
142
  fetch: appFetch,
148
143
  },
@@ -151,6 +146,61 @@ export const obtainCredential: IssuanceApi["obtainCredential"] = async (
151
146
  accessToken: accessToken.access_token,
152
147
  dPoP: credentialDPoP.jwt,
153
148
  }).catch(handleObtainCredentialError);
149
+ };
150
+
151
+ export const obtainCredential: IssuanceApi["obtainCredential"] = async (
152
+ issuerConf,
153
+ accessToken,
154
+ clientId,
155
+ credentialDefinition,
156
+ context
157
+ ) => {
158
+ const {
159
+ credentialCryptoContext,
160
+ dPopCryptoContext,
161
+ walletUnitAttestation,
162
+ appFetch = fetch,
163
+ } = context;
164
+ if (!walletUnitAttestation) {
165
+ throw new ValidationFailed({
166
+ message:
167
+ "The Wallet Unit Attestation is required to obtain the credential",
168
+ });
169
+ }
170
+
171
+ const { credential_configuration_id, credential_identifier } =
172
+ credentialDefinition;
173
+
174
+ // Validation of accessTokenResponse.authorization_details if contain credentialDefinition
175
+ const containsCredentialDefinition = accessToken.authorization_details.some(
176
+ (c) =>
177
+ c.credential_configuration_id === credential_configuration_id &&
178
+ (credential_identifier
179
+ ? c.credential_identifiers.includes(credential_identifier)
180
+ : true)
181
+ );
182
+
183
+ if (!containsCredentialDefinition) {
184
+ Logger.log(
185
+ LogLevel.ERROR,
186
+ `Credential definition not found in the access token response ${accessToken.authorization_details}`
187
+ );
188
+ throw new ValidationFailed({
189
+ message:
190
+ "The access token response does not contain the requested credential",
191
+ });
192
+ }
193
+
194
+ const credentialRes = await requestCredentials({
195
+ issuerConf,
196
+ accessToken,
197
+ clientId,
198
+ credentialCryptoContexts: [credentialCryptoContext],
199
+ credentialIdentifier: credential_identifier!,
200
+ dPopCryptoContext,
201
+ keyAttestationJwt: walletUnitAttestation,
202
+ appFetch,
203
+ });
154
204
 
155
205
  Logger.log(
156
206
  LogLevel.DEBUG,
@@ -172,6 +222,51 @@ export const obtainCredential: IssuanceApi["obtainCredential"] = async (
172
222
  };
173
223
  };
174
224
 
225
+ export const obtainCredentialsBatch: IssuanceApi["obtainCredentialsBatch"] =
226
+ async (issuerConf, accessToken, clientId, credentialDefinition, context) => {
227
+ const {
228
+ credentialCryptoContexts,
229
+ dPopCryptoContext,
230
+ walletUnitAttestation,
231
+ appFetch = fetch,
232
+ } = context;
233
+ if (!walletUnitAttestation) {
234
+ throw new ValidationFailed({
235
+ message:
236
+ "The Wallet Unit Attestation is required to obtain the credential",
237
+ });
238
+ }
239
+
240
+ const { credential_configuration_id, credential_identifier } =
241
+ credentialDefinition;
242
+
243
+ const credentialRes = await requestCredentials({
244
+ issuerConf,
245
+ accessToken,
246
+ clientId,
247
+ credentialCryptoContexts,
248
+ credentialIdentifier: credential_identifier,
249
+ dPopCryptoContext,
250
+ keyAttestationJwt: walletUnitAttestation,
251
+ appFetch,
252
+ });
253
+
254
+ // Extract the format corresponding to the credential_configuration_id used
255
+ const issuerCredentialConfig =
256
+ issuerConf.credential_configurations_supported[
257
+ credential_configuration_id
258
+ ];
259
+
260
+ if ("transaction_id" in credentialRes) {
261
+ throw new IoWalletError("Deferred issuance is not currently supported");
262
+ }
263
+
264
+ return credentialRes.credentials.map(({ credential }) => ({
265
+ credential,
266
+ format: issuerCredentialConfig!.format,
267
+ }));
268
+ };
269
+
175
270
  /**
176
271
  * Handle the credential error by mapping it to a custom exception.
177
272
  * If the error is not an instance of {@link SdkUnexpectedStatusCodeError}, it is thrown as is.
@@ -9,7 +9,10 @@ import {
9
9
  getRequestedCredentialToBePresented,
10
10
  } from "./03-complete-user-authorization";
11
11
  import { authorizeAccess } from "./04-authorize-access";
12
- import { obtainCredential } from "./05-obtain-credential";
12
+ import {
13
+ obtainCredential,
14
+ obtainCredentialsBatch,
15
+ } from "./05-obtain-credential";
13
16
  import { verifyAndParseCredential } from "./06-verify-and-parse-credential";
14
17
  import { MRTDPoP } from "../mrtd-pop";
15
18
 
@@ -23,6 +26,7 @@ export const Issuance: IssuanceApi = {
23
26
  completeUserAuthorizationWithFormPostJwtMode,
24
27
  authorizeAccess,
25
28
  obtainCredential,
29
+ obtainCredentialsBatch,
26
30
  verifyAndParseCredential,
27
31
  MRTDPoP,
28
32
  };
@@ -3,7 +3,14 @@ import type { CertificateValidationResult } from "@pagopa/io-react-native-crypto
3
3
  export interface VerifyAuthRequestCertificateChainApi {
4
4
  /**
5
5
  * Verify the X.509 certificate chain in the Request Object `x5c` header claim.
6
- * @since 1.0.0
6
+ *
7
+ * **Note:** the method is optional and might not be present in the interface. Always check for its presence before calling it.
8
+ * @example
9
+ * if (RemotePresentation.verifyAuthRequestCertificateChain) {
10
+ * RemotePresentation.verifyAuthRequestCertificateChain(requestObjectJwt, { caRootCert })
11
+ * }
12
+ *
13
+ * @since 1.3.3
7
14
  *
8
15
  * @param requestObjectJwt The Request Object in JWT format
9
16
  * @param params.caRootCert The CA root certificate used to validate the chain
@@ -11,7 +18,7 @@ export interface VerifyAuthRequestCertificateChainApi {
11
18
  * @throws {MissingX509CertsError} if the Request Object does not contain x5c
12
19
  * @throws {X509ValidationError} if the certificate chain validation fails
13
20
  */
14
- verifyAuthRequestCertificateChain(
21
+ verifyAuthRequestCertificateChain?(
15
22
  requestObjectJwt: string,
16
23
  params: {
17
24
  caRootCert: string;
@@ -8,7 +8,7 @@ export interface VerifyRequestObjectApi {
8
8
  *
9
9
  * @param requestObjectEncodedJwt The Request Object in JWT format
10
10
  * @param params.clientId The client ID to verify
11
- * @param params.rpConf The Entity Configuration of the Relying Party
11
+ * @param params.rpConf Optional Relying Party configuration (OpenID Federation clients only)
12
12
  * @param params.state Optional state
13
13
  * @returns The verified Request Object
14
14
  * @throws {InvalidRequestObjectError} if the Request Object cannot be validated
@@ -17,7 +17,7 @@ export interface VerifyRequestObjectApi {
17
17
  requestObjectEncodedJwt: string,
18
18
  params: {
19
19
  clientId: string;
20
- rpConf: RelyingPartyConfig;
20
+ rpConf?: RelyingPartyConfig;
21
21
  state?: string;
22
22
  }
23
23
  ): Promise<{ requestObject: RequestObject }>;
@@ -38,14 +38,14 @@ export interface SendAuthorizationResponseApi {
38
38
  *
39
39
  * @param requestObject The request details, including presentation requirements.
40
40
  * @param remotePresentation The presentations to send, each with their VP token
41
- * @param rpConf The Relying Party common configuration
41
+ * @param rpConf Optional Relying Party configuration (OpenID Federation clients only)
42
42
  * @param context Contains optional custom fetch implementation.
43
43
  * @returns Parsed and validated authorization response from the Relying Party.
44
44
  */
45
45
  sendAuthorizationResponse(
46
46
  requestObject: RequestObject,
47
47
  remotePresentation: RemotePresentation,
48
- rpConf: RelyingPartyConfig,
48
+ rpConf?: RelyingPartyConfig,
49
49
  context?: FetchContext
50
50
  ): Promise<AuthorizationResponse>;
51
51
 
@@ -1,5 +1,6 @@
1
1
  import * as z from "zod";
2
2
  import type { CryptoContext } from "@pagopa/io-react-native-jwt";
3
+ import type { jsonWebKeySet } from "@pagopa/io-wallet-oid-federation";
3
4
  import type { SupportedSdJwtLegacyFormat } from "../../../sd-jwt/types";
4
5
 
5
6
  export type PresentationParams = z.infer<typeof PresentationParams>;
@@ -68,6 +69,18 @@ export type RemotePresentationDetails = {
68
69
  vpToken: string;
69
70
  };
70
71
 
72
+ type ClientMetadata = {
73
+ jwks: jsonWebKeySet;
74
+ encrypted_response_enc_values_supported: string[];
75
+ client_id: string;
76
+ client_name: string;
77
+ logo_uri: string;
78
+ application_type: "web";
79
+ request_uris: string[];
80
+ response_uris: string[];
81
+ vp_formats_supported: Record<string, { "sd-jwt_alg_values"?: string[] }>;
82
+ };
83
+
71
84
  /**
72
85
  * Common Request Object type, decoupled from specific IT-Wallet versions
73
86
  */
@@ -80,6 +93,9 @@ export type RequestObject = {
80
93
  dcql_query: Record<string, unknown>;
81
94
  response_type: "vp_token";
82
95
  response_mode: "direct_post.jwt";
96
+ x5c?: string[];
97
+ trust_chain?: string[];
98
+ client_metadata?: ClientMetadata;
83
99
  };
84
100
 
85
101
  /**
@@ -1,13 +1,20 @@
1
1
  import { decode as decodeJwt, verify } from "@pagopa/io-react-native-jwt";
2
2
  import { type z } from "zod";
3
3
  import type { RelyingPartyConfig, RemotePresentationApi } from "../api";
4
+ import { IoWalletError } from "../../../utils/errors";
4
5
  import { InvalidRequestObjectError } from "../common/errors";
5
- import { RequestObjectPayload } from "./types";
6
+ import { RawRequestObject } from "./types";
6
7
  import { mapToRequestObject } from "./mappers";
7
8
  import { getJwksFromRpConfig } from "./utils.jwks";
8
9
 
9
10
  export const verifyRequestObject: RemotePresentationApi["verifyRequestObject"] =
10
11
  async (requestObjectEncodedJwt, { clientId, rpConf, state }) => {
12
+ if (!rpConf) {
13
+ throw new IoWalletError(
14
+ "Relying Party Configuration is required for OpenID Federation clients"
15
+ );
16
+ }
17
+
11
18
  const requestObjectJwt = decodeJwt(requestObjectEncodedJwt);
12
19
 
13
20
  const pubKey = getSigPublicKey(
@@ -24,10 +31,14 @@ export const verifyRequestObject: RemotePresentationApi["verifyRequestObject"] =
24
31
  );
25
32
  }
26
33
 
27
- const requestObject = validateRequestObjectShape(requestObjectJwt.payload);
34
+ const rawRequestObject = validateRequestObjectShape({
35
+ header: requestObjectJwt.protectedHeader,
36
+ payload: requestObjectJwt.payload,
37
+ });
28
38
 
29
39
  const isClientIdMatch =
30
- clientId === requestObject.client_id && clientId === rpConf.subject;
40
+ clientId === rawRequestObject.payload.client_id &&
41
+ clientId === rpConf.subject;
31
42
 
32
43
  if (!isClientIdMatch) {
33
44
  throw new InvalidRequestObjectError(
@@ -35,15 +46,15 @@ export const verifyRequestObject: RemotePresentationApi["verifyRequestObject"] =
35
46
  );
36
47
  }
37
48
 
38
- const isStateMatch = state ? state === requestObject.state : true;
39
-
40
- if (!isStateMatch) {
49
+ if (state && state !== rawRequestObject.payload.state) {
41
50
  throw new InvalidRequestObjectError(
42
51
  "The provided state does not match the Request Object's"
43
52
  );
44
53
  }
45
54
 
46
- return { requestObject: mapToRequestObject(requestObject) };
55
+ return {
56
+ requestObject: mapToRequestObject(rawRequestObject),
57
+ };
47
58
  };
48
59
 
49
60
  /**
@@ -53,8 +64,8 @@ export const verifyRequestObject: RemotePresentationApi["verifyRequestObject"] =
53
64
  * @returns A valid Request Object
54
65
  * @throws {InvalidRequestObjectError} when the Request Object cannot be parsed
55
66
  */
56
- const validateRequestObjectShape = (payload: unknown): RequestObjectPayload => {
57
- const requestObjectParse = RequestObjectPayload.safeParse(payload);
67
+ const validateRequestObjectShape = (payload: unknown): RawRequestObject => {
68
+ const requestObjectParse = RawRequestObject.safeParse(payload);
58
69
 
59
70
  if (requestObjectParse.success) {
60
71
  return requestObjectParse.data;
@@ -97,7 +108,7 @@ const getSigPublicKey = (
97
108
  * Utility to format flattened Zod errors into a simplified string `key1: key1_error, key2: key2_error`
98
109
  */
99
110
  const formatFlattenedZodErrors = (
100
- errors: z.core.$ZodFlattenedError<RequestObjectPayload>
111
+ errors: z.core.$ZodFlattenedError<RawRequestObject>
101
112
  ): string =>
102
113
  Object.entries(errors.fieldErrors)
103
114
  .map(([key, error]) => `${key}: ${error[0]}`)
@@ -3,6 +3,7 @@ import { NoSuitableKeysFoundInEntityConfiguration } from "../common/errors";
3
3
  import { hasStatusOrThrow } from "../../../utils/misc";
4
4
  import type { JWK } from "../../../utils/jwk";
5
5
  import {
6
+ IoWalletError,
6
7
  RelyingPartyResponseError,
7
8
  RelyingPartyResponseErrorCodes,
8
9
  ResponseErrorBuilder,
@@ -118,6 +119,12 @@ export const sendAuthorizationResponse: RemotePresentationApi["sendAuthorization
118
119
  rpConf,
119
120
  { appFetch = fetch } = {}
120
121
  ) => {
122
+ if (!rpConf) {
123
+ throw new IoWalletError(
124
+ "Relying Party Configuration is required for OpenID Federation clients"
125
+ );
126
+ }
127
+
121
128
  const { presentations } = remotePresentation;
122
129
  // 1. Prepare the VP token as a JSON object with keys corresponding to the DCQL query credential IDs
123
130
  const requestBody = await buildDirectPostJwtBody(requestObject, rpConf, {
@@ -2,7 +2,6 @@ import type { RemotePresentationApi } from "../api";
2
2
  import { startFlowFromQR } from "./01-start-flow";
3
3
  import { evaluateRelyingPartyTrust } from "./02-evaluate-rp-trust";
4
4
  import { getRequestObject } from "./03-get-request-object";
5
- import { verifyAuthRequestCertificateChain } from "./04-verify-certificate-chain";
6
5
  import { verifyRequestObject } from "./05-verify-request-object";
7
6
  import { evaluateDcqlQuery } from "./06-evaluate-dcql-query";
8
7
  import {
@@ -15,7 +14,6 @@ export const RemotePresentation: RemotePresentationApi = {
15
14
  startFlowFromQR,
16
15
  evaluateRelyingPartyTrust,
17
16
  getRequestObject,
18
- verifyAuthRequestCertificateChain,
19
17
  verifyRequestObject,
20
18
  evaluateDcqlQuery,
21
19
  prepareRemotePresentations,
@@ -2,15 +2,15 @@ import { createMapper } from "../../../utils/mappers";
2
2
  import { RelyingPartyEntityConfiguration } from "../../../trust/v1.0.0/types";
3
3
  import type { RelyingPartyConfig } from "../api";
4
4
  import type { RequestObject } from "../api/types";
5
- import { RequestObjectPayload } from "./types";
5
+ import { RawRequestObject } from "./types";
6
6
 
7
7
  export const mapToRelyingPartyConfig = createMapper<
8
8
  RelyingPartyEntityConfiguration,
9
9
  RelyingPartyConfig
10
- >((x) => {
11
- const { federation_entity, openid_credential_verifier } = x.payload.metadata;
10
+ >(({ payload }) => {
11
+ const { federation_entity, openid_credential_verifier } = payload.metadata;
12
12
  return {
13
- subject: x.payload.sub,
13
+ subject: payload.sub,
14
14
  jwks: openid_credential_verifier.jwks,
15
15
  authorization_encrypted_response_alg:
16
16
  openid_credential_verifier.authorization_encrypted_response_alg,
@@ -20,16 +20,16 @@ export const mapToRelyingPartyConfig = createMapper<
20
20
  };
21
21
  });
22
22
 
23
- export const mapToRequestObject = createMapper<
24
- RequestObjectPayload,
25
- RequestObject
26
- >((x) => ({
27
- iss: x.iss,
28
- client_id: x.client_id,
29
- dcql_query: x.dcql_query,
30
- nonce: x.nonce,
31
- response_uri: x.response_uri,
32
- state: x.state,
33
- response_mode: x.response_mode,
34
- response_type: x.response_type,
35
- }));
23
+ export const mapToRequestObject = createMapper<RawRequestObject, RequestObject>(
24
+ ({ header, payload }) => ({
25
+ iss: payload.iss,
26
+ client_id: payload.client_id,
27
+ dcql_query: payload.dcql_query,
28
+ nonce: payload.nonce,
29
+ response_uri: payload.response_uri,
30
+ state: payload.state,
31
+ response_mode: payload.response_mode,
32
+ response_type: payload.response_type,
33
+ trust_chain: header.trust_chain,
34
+ })
35
+ );
@@ -2,21 +2,29 @@ import * as z from "zod";
2
2
  import { UnixTime } from "../../../utils/zod";
3
3
  import { ErrorResponse } from "../api/types";
4
4
 
5
- export type RequestObjectPayload = z.infer<typeof RequestObjectPayload>;
6
- export const RequestObjectPayload = z.object({
7
- iss: z.string(),
8
- iat: UnixTime,
9
- exp: UnixTime,
10
- state: z.string(),
11
- nonce: z.string(),
12
- response_uri: z.string(),
13
- request_uri_method: z.string().optional(),
14
- response_type: z.literal("vp_token"),
15
- response_mode: z.literal("direct_post.jwt"),
16
- client_id: z.string(),
17
- dcql_query: z.record(z.string(), z.any()), // Validation happens within the `dcql` library, no need to duplicate it here
18
- scope: z.string().optional(),
19
- wallet_nonce: z.string().optional(),
5
+ export type RawRequestObject = z.infer<typeof RawRequestObject>;
6
+ export const RawRequestObject = z.object({
7
+ header: z.object({
8
+ alg: z.string(),
9
+ kid: z.string(),
10
+ typ: z.literal("oauth-authz-req+jwt"),
11
+ trust_chain: z.array(z.string()).optional(),
12
+ }),
13
+ payload: z.object({
14
+ iss: z.string(),
15
+ iat: UnixTime,
16
+ exp: UnixTime,
17
+ state: z.string(),
18
+ nonce: z.string(),
19
+ response_uri: z.string(),
20
+ request_uri_method: z.string().optional(),
21
+ response_type: z.literal("vp_token"),
22
+ response_mode: z.literal("direct_post.jwt"),
23
+ client_id: z.string(),
24
+ dcql_query: z.record(z.string(), z.any()), // Validation happens within the `dcql` library, no need to duplicate it here
25
+ scope: z.string().optional(),
26
+ wallet_nonce: z.string().optional(),
27
+ }),
20
28
  });
21
29
 
22
30
  /**