@pagopa/io-react-native-wallet 0.12.0 → 0.13.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 (205) hide show
  1. package/lib/commonjs/client/generated/wallet-provider.js +22 -22
  2. package/lib/commonjs/client/generated/wallet-provider.js.map +1 -1
  3. package/lib/commonjs/client/index.js +1 -2
  4. package/lib/commonjs/client/index.js.map +1 -1
  5. package/lib/commonjs/credential/issuance/02-evaluate-issuer-trust.js +2 -1
  6. package/lib/commonjs/credential/issuance/02-evaluate-issuer-trust.js.map +1 -1
  7. package/lib/commonjs/credential/issuance/03-start-credential-issuance.js +287 -0
  8. package/lib/commonjs/credential/issuance/03-start-credential-issuance.js.map +1 -0
  9. package/lib/commonjs/credential/issuance/03-start-user-authorization.js +56 -83
  10. package/lib/commonjs/credential/issuance/03-start-user-authorization.js.map +1 -1
  11. package/lib/commonjs/credential/issuance/04-complete-user-authorization.js +88 -0
  12. package/lib/commonjs/credential/issuance/04-complete-user-authorization.js.map +1 -1
  13. package/lib/commonjs/credential/issuance/05-authorize-access.js +56 -33
  14. package/lib/commonjs/credential/issuance/05-authorize-access.js.map +1 -1
  15. package/lib/commonjs/credential/issuance/06-obtain-credential.js +51 -78
  16. package/lib/commonjs/credential/issuance/06-obtain-credential.js.map +1 -1
  17. package/lib/commonjs/credential/issuance/07-verify-and-parse-credential.js +21 -44
  18. package/lib/commonjs/credential/issuance/07-verify-and-parse-credential.js.map +1 -1
  19. package/lib/commonjs/credential/issuance/index.js +7 -0
  20. package/lib/commonjs/credential/issuance/index.js.map +1 -1
  21. package/lib/commonjs/credential/issuance/types.js +28 -0
  22. package/lib/commonjs/credential/issuance/types.js.map +1 -0
  23. package/lib/commonjs/index.js.map +1 -1
  24. package/lib/commonjs/pid/sd-jwt/converters.js +5 -9
  25. package/lib/commonjs/pid/sd-jwt/converters.js.map +1 -1
  26. package/lib/commonjs/pid/sd-jwt/types.js +3 -3
  27. package/lib/commonjs/pid/sd-jwt/types.js.map +1 -1
  28. package/lib/commonjs/sd-jwt/__test__/converters.test.js +1 -1
  29. package/lib/commonjs/sd-jwt/__test__/converters.test.js.map +1 -1
  30. package/lib/commonjs/sd-jwt/__test__/index.test.js +30 -43
  31. package/lib/commonjs/sd-jwt/__test__/index.test.js.map +1 -1
  32. package/lib/commonjs/sd-jwt/__test__/types.test.js +16 -24
  33. package/lib/commonjs/sd-jwt/__test__/types.test.js.map +1 -1
  34. package/lib/commonjs/sd-jwt/index.js +3 -9
  35. package/lib/commonjs/sd-jwt/index.js.map +1 -1
  36. package/lib/commonjs/sd-jwt/types.js +11 -16
  37. package/lib/commonjs/sd-jwt/types.js.map +1 -1
  38. package/lib/commonjs/trust/types.js +70 -29
  39. package/lib/commonjs/trust/types.js.map +1 -1
  40. package/lib/commonjs/utils/auth.js +44 -0
  41. package/lib/commonjs/utils/auth.js.map +1 -0
  42. package/lib/commonjs/utils/errors.js +77 -2
  43. package/lib/commonjs/utils/errors.js.map +1 -1
  44. package/lib/commonjs/utils/misc.js +34 -1
  45. package/lib/commonjs/utils/misc.js.map +1 -1
  46. package/lib/commonjs/utils/par.js +23 -15
  47. package/lib/commonjs/utils/par.js.map +1 -1
  48. package/lib/commonjs/utils/pop.js +33 -0
  49. package/lib/commonjs/utils/pop.js.map +1 -0
  50. package/lib/commonjs/wallet-instance-attestation/issuing.js +17 -2
  51. package/lib/commonjs/wallet-instance-attestation/issuing.js.map +1 -1
  52. package/lib/commonjs/wallet-instance-attestation/types.js +7 -7
  53. package/lib/commonjs/wallet-instance-attestation/types.js.map +1 -1
  54. package/lib/module/client/generated/wallet-provider.js +16 -19
  55. package/lib/module/client/generated/wallet-provider.js.map +1 -1
  56. package/lib/module/client/index.js +1 -2
  57. package/lib/module/client/index.js.map +1 -1
  58. package/lib/module/credential/issuance/02-evaluate-issuer-trust.js +2 -1
  59. package/lib/module/credential/issuance/02-evaluate-issuer-trust.js.map +1 -1
  60. package/lib/module/credential/issuance/03-start-credential-issuance.js +276 -0
  61. package/lib/module/credential/issuance/03-start-credential-issuance.js.map +1 -0
  62. package/lib/module/credential/issuance/03-start-user-authorization.js +56 -80
  63. package/lib/module/credential/issuance/03-start-user-authorization.js.map +1 -1
  64. package/lib/module/credential/issuance/04-complete-user-authorization.js +85 -1
  65. package/lib/module/credential/issuance/04-complete-user-authorization.js.map +1 -1
  66. package/lib/module/credential/issuance/05-authorize-access.js +54 -33
  67. package/lib/module/credential/issuance/05-authorize-access.js.map +1 -1
  68. package/lib/module/credential/issuance/06-obtain-credential.js +50 -75
  69. package/lib/module/credential/issuance/06-obtain-credential.js.map +1 -1
  70. package/lib/module/credential/issuance/07-verify-and-parse-credential.js +21 -44
  71. package/lib/module/credential/issuance/07-verify-and-parse-credential.js.map +1 -1
  72. package/lib/module/credential/issuance/index.js +2 -1
  73. package/lib/module/credential/issuance/index.js.map +1 -1
  74. package/lib/module/credential/issuance/types.js +18 -0
  75. package/lib/module/credential/issuance/types.js.map +1 -0
  76. package/lib/module/index.js.map +1 -1
  77. package/lib/module/pid/sd-jwt/converters.js +5 -9
  78. package/lib/module/pid/sd-jwt/converters.js.map +1 -1
  79. package/lib/module/pid/sd-jwt/types.js +3 -3
  80. package/lib/module/pid/sd-jwt/types.js.map +1 -1
  81. package/lib/module/sd-jwt/__test__/converters.test.js +1 -1
  82. package/lib/module/sd-jwt/__test__/converters.test.js.map +1 -1
  83. package/lib/module/sd-jwt/__test__/index.test.js +30 -43
  84. package/lib/module/sd-jwt/__test__/index.test.js.map +1 -1
  85. package/lib/module/sd-jwt/__test__/types.test.js +16 -24
  86. package/lib/module/sd-jwt/__test__/types.test.js.map +1 -1
  87. package/lib/module/sd-jwt/index.js +3 -9
  88. package/lib/module/sd-jwt/index.js.map +1 -1
  89. package/lib/module/sd-jwt/types.js +11 -16
  90. package/lib/module/sd-jwt/types.js.map +1 -1
  91. package/lib/module/sd-jwt/verifier.js.map +1 -1
  92. package/lib/module/trust/types.js +70 -29
  93. package/lib/module/trust/types.js.map +1 -1
  94. package/lib/module/utils/auth.js +35 -0
  95. package/lib/module/utils/auth.js.map +1 -0
  96. package/lib/module/utils/errors.js +71 -0
  97. package/lib/module/utils/errors.js.map +1 -1
  98. package/lib/module/utils/misc.js +31 -0
  99. package/lib/module/utils/misc.js.map +1 -1
  100. package/lib/module/utils/par.js +24 -16
  101. package/lib/module/utils/par.js.map +1 -1
  102. package/lib/module/utils/pop.js +24 -0
  103. package/lib/module/utils/pop.js.map +1 -0
  104. package/lib/module/wallet-instance-attestation/issuing.js +17 -2
  105. package/lib/module/wallet-instance-attestation/issuing.js.map +1 -1
  106. package/lib/module/wallet-instance-attestation/types.js +7 -7
  107. package/lib/module/wallet-instance-attestation/types.js.map +1 -1
  108. package/lib/typescript/client/generated/wallet-provider.d.ts +35 -13
  109. package/lib/typescript/client/generated/wallet-provider.d.ts.map +1 -1
  110. package/lib/typescript/client/index.d.ts.map +1 -1
  111. package/lib/typescript/credential/issuance/01-start-flow.d.ts +1 -0
  112. package/lib/typescript/credential/issuance/01-start-flow.d.ts.map +1 -1
  113. package/lib/typescript/credential/issuance/02-evaluate-issuer-trust.d.ts +2 -1
  114. package/lib/typescript/credential/issuance/02-evaluate-issuer-trust.d.ts.map +1 -1
  115. package/lib/typescript/credential/issuance/03-start-credential-issuance.d.ts +41 -0
  116. package/lib/typescript/credential/issuance/03-start-credential-issuance.d.ts.map +1 -0
  117. package/lib/typescript/credential/issuance/03-start-user-authorization.d.ts +23 -18
  118. package/lib/typescript/credential/issuance/03-start-user-authorization.d.ts.map +1 -1
  119. package/lib/typescript/credential/issuance/04-complete-user-authorization.d.ts +24 -12
  120. package/lib/typescript/credential/issuance/04-complete-user-authorization.d.ts.map +1 -1
  121. package/lib/typescript/credential/issuance/05-authorize-access.d.ts +22 -16
  122. package/lib/typescript/credential/issuance/05-authorize-access.d.ts.map +1 -1
  123. package/lib/typescript/credential/issuance/06-obtain-credential.d.ts +19 -26
  124. package/lib/typescript/credential/issuance/06-obtain-credential.d.ts.map +1 -1
  125. package/lib/typescript/credential/issuance/07-verify-and-parse-credential.d.ts +10 -15
  126. package/lib/typescript/credential/issuance/07-verify-and-parse-credential.d.ts.map +1 -1
  127. package/lib/typescript/credential/issuance/index.d.ts +3 -4
  128. package/lib/typescript/credential/issuance/index.d.ts.map +1 -1
  129. package/lib/typescript/credential/issuance/types.d.ts +63 -0
  130. package/lib/typescript/credential/issuance/types.d.ts.map +1 -0
  131. package/lib/typescript/credential/presentation/types.d.ts +6 -6
  132. package/lib/typescript/index.d.ts +2 -1
  133. package/lib/typescript/index.d.ts.map +1 -1
  134. package/lib/typescript/pid/sd-jwt/converters.d.ts.map +1 -1
  135. package/lib/typescript/pid/sd-jwt/types.d.ts +36 -36
  136. package/lib/typescript/pid/sd-jwt/types.d.ts.map +1 -1
  137. package/lib/typescript/sd-jwt/index.d.ts +40 -68
  138. package/lib/typescript/sd-jwt/index.d.ts.map +1 -1
  139. package/lib/typescript/sd-jwt/types.d.ts +64 -121
  140. package/lib/typescript/sd-jwt/types.d.ts.map +1 -1
  141. package/lib/typescript/trust/index.d.ts +150 -48
  142. package/lib/typescript/trust/index.d.ts.map +1 -1
  143. package/lib/typescript/trust/types.d.ts +2838 -1740
  144. package/lib/typescript/trust/types.d.ts.map +1 -1
  145. package/lib/typescript/utils/auth.d.ts +52 -0
  146. package/lib/typescript/utils/auth.d.ts.map +1 -0
  147. package/lib/typescript/utils/errors.d.ts +36 -1
  148. package/lib/typescript/utils/errors.d.ts.map +1 -1
  149. package/lib/typescript/utils/integrity.d.ts +1 -1
  150. package/lib/typescript/utils/misc.d.ts +18 -0
  151. package/lib/typescript/utils/misc.d.ts.map +1 -1
  152. package/lib/typescript/utils/par.d.ts +8 -31
  153. package/lib/typescript/utils/par.d.ts.map +1 -1
  154. package/lib/typescript/utils/pop.d.ts +26 -0
  155. package/lib/typescript/utils/pop.d.ts.map +1 -0
  156. package/lib/typescript/wallet-instance-attestation/issuing.d.ts +2 -1
  157. package/lib/typescript/wallet-instance-attestation/issuing.d.ts.map +1 -1
  158. package/lib/typescript/wallet-instance-attestation/types.d.ts +59 -59
  159. package/lib/typescript/wallet-instance-attestation/types.d.ts.map +1 -1
  160. package/package.json +2 -1
  161. package/src/client/generated/wallet-provider.ts +24 -21
  162. package/src/client/index.ts +3 -8
  163. package/src/credential/issuance/01-start-flow.ts +1 -0
  164. package/src/credential/issuance/02-evaluate-issuer-trust.ts +2 -1
  165. package/src/credential/issuance/03-start-credential-issuance.ts +407 -0
  166. package/src/credential/issuance/03-start-user-authorization.ts +91 -92
  167. package/src/credential/issuance/04-complete-user-authorization.ts +114 -13
  168. package/src/credential/issuance/05-authorize-access.ts +74 -49
  169. package/src/credential/issuance/06-obtain-credential.ts +77 -111
  170. package/src/credential/issuance/07-verify-and-parse-credential.ts +30 -67
  171. package/src/credential/issuance/index.ts +6 -4
  172. package/src/credential/issuance/types.ts +25 -0
  173. package/src/index.ts +2 -1
  174. package/src/pid/sd-jwt/converters.ts +5 -11
  175. package/src/pid/sd-jwt/types.ts +8 -6
  176. package/src/sd-jwt/__test__/converters.test.ts +1 -1
  177. package/src/sd-jwt/__test__/index.test.ts +45 -74
  178. package/src/sd-jwt/__test__/types.test.ts +21 -33
  179. package/src/sd-jwt/index.ts +3 -12
  180. package/src/sd-jwt/types.ts +17 -22
  181. package/src/trust/types.ts +64 -32
  182. package/src/utils/auth.ts +37 -0
  183. package/src/utils/errors.ts +85 -1
  184. package/src/utils/integrity.ts +1 -1
  185. package/src/utils/misc.ts +43 -0
  186. package/src/utils/par.ts +29 -17
  187. package/src/utils/pop.ts +34 -0
  188. package/src/wallet-instance-attestation/issuing.ts +39 -2
  189. package/src/wallet-instance-attestation/types.ts +11 -7
  190. package/lib/commonjs/credential/issuance/07-confirm-credential.js +0 -6
  191. package/lib/commonjs/credential/issuance/07-confirm-credential.js.map +0 -1
  192. package/lib/commonjs/credential/issuance/08-confirm-credential.js +0 -6
  193. package/lib/commonjs/credential/issuance/08-confirm-credential.js.map +0 -1
  194. package/lib/module/credential/issuance/07-confirm-credential.js +0 -2
  195. package/lib/module/credential/issuance/07-confirm-credential.js.map +0 -1
  196. package/lib/module/credential/issuance/08-confirm-credential.js +0 -2
  197. package/lib/module/credential/issuance/08-confirm-credential.js.map +0 -1
  198. package/lib/typescript/credential/issuance/07-confirm-credential.d.ts +0 -11
  199. package/lib/typescript/credential/issuance/07-confirm-credential.d.ts.map +0 -1
  200. package/lib/typescript/credential/issuance/08-confirm-credential.d.ts +0 -11
  201. package/lib/typescript/credential/issuance/08-confirm-credential.d.ts.map +0 -1
  202. package/src/credential/issuance/07-confirm-credential.ts +0 -14
  203. package/src/credential/issuance/08-confirm-credential.ts +0 -14
  204. package/src/sd-jwt/__test__/converters.test.js +0 -24
  205. package/src/sd-jwt/verifier.js +0 -12
@@ -1,24 +1,54 @@
1
- import * as z from "zod";
2
- import uuid from "react-native-uuid";
3
- import { AuthorizationDetail, makeParRequest } from "../../utils/par";
4
1
  import type { CryptoContext } from "@pagopa/io-react-native-jwt";
5
- import { getJwtFromFormPost } from "../../utils/decoder";
6
- import { hasStatus, type Out } from "../../utils/misc";
7
- import type { StartFlow } from "./01-start-flow";
2
+ import type { ResponseMode } from "./types";
3
+ import {
4
+ generateRandomAlphaNumericString,
5
+ type Out,
6
+ } from "../../../src/utils/misc";
7
+
8
8
  import type { EvaluateIssuerTrust } from "./02-evaluate-issuer-trust";
9
+ import type { StartFlow } from "./01-start-flow";
10
+ import { AuthorizationDetail, makeParRequest } from "../../../src/utils/par";
9
11
  import { ASSERTION_TYPE } from "./const";
10
12
 
13
+ export type StartUserAuthorization = (
14
+ issuerConf: Out<EvaluateIssuerTrust>["issuerConf"],
15
+ credentialType: Out<StartFlow>["credentialType"],
16
+ context: {
17
+ wiaCryptoContext: CryptoContext;
18
+ walletInstanceAttestation: string;
19
+ redirectUri: string;
20
+ appFetch?: GlobalFetch["fetch"];
21
+ }
22
+ ) => Promise<{
23
+ issuerRequestUri: string;
24
+ clientId: string;
25
+ codeVerifier: string;
26
+ credentialDefinition: AuthorizationDetail;
27
+ }>;
28
+
29
+ /**
30
+ * Ensures that the credential type requested is supported by the issuer and contained in the
31
+ * issuer configuration.
32
+ * @param issuerConf The issuer configuration returned by {@link evaluateIssuerTrust}
33
+ * @param credentialType The type of the credential to be requested returned by {@link startFlow}
34
+ * @param context.wiaCryptoContext The Wallet Instance's crypto context
35
+ * @param context.walletInstanceAttestation The Wallet Instance's attestation
36
+ * @param context.redirectUri The redirect URI which is the custom URL scheme that the Wallet Instance is registered to handle
37
+ * @param context.appFetch (optional) fetch api implementation. Default: built-in fetch
38
+ * @returns The credential definition to be used in the request which includes the format and the type and its type
39
+ */
11
40
  const selectCredentialDefinition = (
12
41
  issuerConf: Out<EvaluateIssuerTrust>["issuerConf"],
13
42
  credentialType: Out<StartFlow>["credentialType"]
14
43
  ): AuthorizationDetail => {
15
- const { credentials_supported } = issuerConf.openid_credential_issuer;
44
+ const credential_configurations_supported =
45
+ issuerConf.openid_credential_issuer.credential_configurations_supported;
16
46
 
17
- const [result] = credentials_supported
18
- .filter((e) => e.credential_definition.type.includes(credentialType))
47
+ const [result] = Object.keys(credential_configurations_supported)
48
+ .filter((e) => e.includes(credentialType))
19
49
  .map((e) => ({
20
- credential_definition: { type: credentialType },
21
- format: e.format,
50
+ credential_configuration_id: credentialType,
51
+ format: credential_configurations_supported[e]!.format,
22
52
  type: "openid_credential" as const,
23
53
  }));
24
54
 
@@ -28,69 +58,46 @@ const selectCredentialDefinition = (
28
58
  return result;
29
59
  };
30
60
 
31
- const decodeAuthorizationResponse = async (
32
- raw: string
33
- ): Promise<{ request_uri: string }> => {
34
- const {
35
- decodedJwt: { payload },
36
- } = await getJwtFromFormPost(raw);
37
-
38
- /**
39
- * FIXME: [SIW-628] This step must not make any difference on the credential
40
- * we are authorizing for, being a PID or any other (Q)EAA.
41
- *
42
- * Currently, PID issuer is implemented to skip the CompleteUserAuthorization step
43
- * thus returning a stubbed (code, state) pair.
44
- *
45
- * This is a workaround to proceeed the flow anyway.
46
- * If the response does not map what expected (CorrectShape),
47
- * we try parse into (code, state) to check if we are in the PID scenario.
48
- * In that case, a stub value is returned (will not be evaluated anyway).
49
- *
50
- * This workaround will be obsolete once the PID issuer fixes its implementation
51
- */
52
- const CorrectShape = z.object({ request_uri: z.string() });
53
- const WrongShapeForPID = z.object({ code: z.string(), state: z.string() });
61
+ /**
62
+ * Ensures that the response mode requested is supported by the issuer and contained in the issuer configuration.
63
+ * @param issuerConf The issuer configuration
64
+ * @param credentialType The type of the credential to be requested
65
+ * @returns The response mode to be used in the request, "query" for PersonIdentificationData and "form_post.jwt" for all other types.
66
+ */
67
+ const selectResponseMode = (
68
+ issuerConf: Out<EvaluateIssuerTrust>["issuerConf"],
69
+ credentialType: Out<StartFlow>["credentialType"]
70
+ ): ResponseMode => {
71
+ const responseModeSupported =
72
+ issuerConf.oauth_authorization_server.response_modes_supported;
54
73
 
55
- const [correct, wrong] = [
56
- CorrectShape.safeParse(payload),
57
- WrongShapeForPID.safeParse(payload),
58
- ];
74
+ const responseMode =
75
+ credentialType === "PersonIdentificationData" ? "query" : "form_post.jwt";
59
76
 
60
- if (correct.success) {
61
- return correct.data;
62
- } else if (wrong.success) {
63
- return { request_uri: "https://fake-request-uri" };
77
+ if (!responseModeSupported.includes(responseMode)) {
78
+ throw new Error(`No response mode support the type '${credentialType}'`);
64
79
  }
65
- throw correct.error;
66
- };
67
80
 
68
- export type StartUserAuthorization = (
69
- issuerConf: Out<EvaluateIssuerTrust>["issuerConf"],
70
- credentialType: Out<StartFlow>["credentialType"],
71
- context: {
72
- wiaCryptoContext: CryptoContext;
73
- walletInstanceAttestation: string;
74
- walletProviderBaseUrl: string;
75
- additionalParams?: Record<string, string>;
76
- appFetch?: GlobalFetch["fetch"];
77
- }
78
- ) => Promise<{ requestUri: string; clientId: string }>;
81
+ return responseMode;
82
+ };
79
83
 
80
84
  /**
81
- * Start the User authorization phase.
82
- * Perform the Pushed Authorization Request as defined in OAuth 2.0 protocol.
83
- *
84
- * @param issuerConf The Issuer configuration
85
- * @param credentialType The type of the credential to be requested
86
- * @param context.wiaCryptoContext The context to access the key associated with the Wallet Instance Attestation
87
- * @param context.walletInstanceAttestation The Wallet Instance Attestation token
88
- * @param context.walletProviderBaseUrl The base url of the Wallet Provider
89
- * @param context.additionalParams Hash set of parameters to be passed to the authorization endpoint
90
- * (used as a temporary fix until we have a proper User identity in the PID token provider)
91
- * TODO: [SIW-630]
92
- * @param context.appFetch (optional) fetch api implementation. Default: built-in fetch
93
- * @returns The request uri to continue the authorization to
85
+ * WARNING: This function must be called after {@link evaluateIssuerTrust} and {@link startFlow}. The next steam is {@link compeUserAuthorizationWithQueryMode} or {@link compeUserAuthorizationWithFormPostJwtMode}
86
+ * Creates and sends a PAR request to the /as/par endpoint of the authroization server.
87
+ * This starts the authentication flow to obtain an access token.
88
+ * This token enables the Wallet Instance to request a digital credential from the Credential Endpoint of the Credential Issuer.
89
+ * This is an HTTP POST request containing the Wallet Instance identifier (client id), the code challenge and challenge method as specified by PKCE according to RFC 9126
90
+ * along with the WTE and its proof of possession (WTE-PoP).
91
+ * Additionally, it includes a request object, which is a signed JWT encapsulating the type of digital credential requested (authorization_details),
92
+ * the application session identifier on the Wallet Instance side (state),
93
+ * the method (query or form_post.jwt) by which the Authorization Server
94
+ * should transmit the Authorization Response containing the authorization code issued upon the end user's authentication (response_mode)
95
+ * to the Wallet Instance's Token Endpoint to obtain the Access Token, and the redirect_uri of the Wallet Instance where the Authorization Response
96
+ * should be delivered. The redirect is achived by using a custom URL scheme that the Wallet Instance is registered to handle.
97
+ * @param issuerConf The issuer configuration
98
+ * @param credentialType The type of the credential to be requested returned by {@link selectCredentialDefinition}
99
+ * @param ctx The context object containing the Wallet Instance's cryptographic context, the Wallet Instance's attestation, the redirect URI and the fetch implementation
100
+ * @returns The URI to which the end user should be redirected to start the authentication flow, along with the client id, the code verifier and the credential definition
94
101
  */
95
102
  export const startUserAuthorization: StartUserAuthorization = async (
96
103
  issuerConf,
@@ -100,39 +107,31 @@ export const startUserAuthorization: StartUserAuthorization = async (
100
107
  const {
101
108
  wiaCryptoContext,
102
109
  walletInstanceAttestation,
103
- walletProviderBaseUrl,
104
- additionalParams = {},
110
+ redirectUri,
105
111
  appFetch = fetch,
106
112
  } = ctx;
113
+
107
114
  const clientId = await wiaCryptoContext.getPublicKey().then((_) => _.kid);
108
- const codeVerifier = `${uuid.v4()}`;
109
- // Make a PAR request to the credential issuer and return the response url
110
- const parUrl =
111
- issuerConf.openid_credential_issuer.pushed_authorization_request_endpoint;
115
+ const codeVerifier = generateRandomAlphaNumericString(64);
116
+ const parEndpoint =
117
+ issuerConf.oauth_authorization_server.pushed_authorization_request_endpoint;
118
+ const credentialDefinition = selectCredentialDefinition(
119
+ issuerConf,
120
+ credentialType
121
+ );
122
+ const responseMode = selectResponseMode(issuerConf, credentialType);
123
+
112
124
  const getPar = makeParRequest({ wiaCryptoContext, appFetch });
113
125
  const issuerRequestUri = await getPar(
114
126
  clientId,
115
127
  codeVerifier,
116
- walletProviderBaseUrl,
117
- parUrl,
128
+ redirectUri,
129
+ responseMode,
130
+ parEndpoint,
118
131
  walletInstanceAttestation,
119
- [selectCredentialDefinition(issuerConf, credentialType)],
132
+ [credentialDefinition],
120
133
  ASSERTION_TYPE
121
134
  );
122
135
 
123
- // Initialize authorization by requesting the authz request uri
124
- const authzRequestEndpoint =
125
- issuerConf.openid_credential_issuer.authorization_endpoint;
126
- const params = new URLSearchParams({
127
- client_id: clientId,
128
- request_uri: issuerRequestUri,
129
- ...additionalParams,
130
- });
131
-
132
- const { request_uri } = await appFetch(`${authzRequestEndpoint}?${params}`)
133
- .then(hasStatus(200))
134
- .then((res) => res.text())
135
- .then(decodeAuthorizationResponse);
136
-
137
- return { requestUri: request_uri, clientId };
136
+ return { issuerRequestUri, clientId, codeVerifier, credentialDefinition };
138
137
  };
@@ -1,17 +1,118 @@
1
- import type { Out } from "../../utils/misc";
1
+ import {
2
+ AuthorizationErrorShape,
3
+ AuthorizationResultShape,
4
+ type AuthorizationContext,
5
+ type AuthorizationResult,
6
+ } from "../../../src/utils/auth";
7
+ import { until, type Out } from "../../utils/misc";
2
8
  import type { StartUserAuthorization } from "./03-start-user-authorization";
9
+ import parseUrl from "parse-url";
10
+ import { AuthorizationError, AuthorizationIdpError } from "../../utils/errors";
11
+ import type { EvaluateIssuerTrust } from "./02-evaluate-issuer-trust";
12
+ import { Linking } from "react-native";
3
13
 
4
14
  /**
5
- * The interface of the phase to complete User authorization.
6
- * It may be implemented as a Credential presentation
7
- * or with a strong User identification
8
- *
9
- * @param requestUri The url to reach to complete the user authorization.
10
- * @param cliendId Identifies the current client across all the requests of the issuing flow
11
- *
12
- * @returns the access code to use to request the credental
15
+ * The interface of the phase to complete User authorization via strong identification when the response mode is "query" and the request credential is a PersonIdentificationData.
13
16
  */
14
- export type CompleteUserAuthorization = (
15
- requestUri: Out<StartUserAuthorization>["requestUri"],
16
- clientId: Out<StartUserAuthorization>["clientId"]
17
- ) => Promise<{ code: string }>;
17
+ export type CompleteUserAuthorizationWithQueryMode = (
18
+ issuerRequestUri: Out<StartUserAuthorization>["issuerRequestUri"],
19
+ clientId: Out<StartUserAuthorization>["clientId"],
20
+ issuerConf: Out<EvaluateIssuerTrust>["issuerConf"],
21
+ idpHint: string,
22
+ redirectUri: string,
23
+ authorizationContext?: AuthorizationContext
24
+ ) => Promise<AuthorizationResult>;
25
+
26
+ /**
27
+ * WARNING: This function must be called after {@link startUserAuthorization}. The next function to be called is {@link authorizeAccess}.
28
+ * The interface of the phase to complete User authorization via strong identification when the response mode is "query" and the request credential is a PersonIdentificationData.
29
+ * It is used to complete the user authorization by catching the redirectSchema from the authorization server which then contains the authorization response.
30
+ * This function utilizes the authorization context to open an in-app browser capable of catching the redirectSchema to perform a get request to the authorization endpoint.
31
+ * If the 302 redirect happens and the redirectSchema is caught, the function will return the authorization response after parsing it from the query string.
32
+ * @param issuerRequestUri the URI of the issuer where the request is sent
33
+ * @param clientId Identifies the current client across all the requests of the issuing flow returned by {@link startUserAuthorization}
34
+ * @param issuerConf The issuer configuration returned by {@link evaluateIssuerTrust}
35
+ * @param authorizationContext The context to identify the user which will be used to start the authorization. It's needed only when requesting a PersonalIdentificationData credential. The implementantion should open an in-app browser capable of catching the redirectSchema.
36
+ * If not specified, the default browser is used
37
+ * @param idphint Unique identifier of the SPID IDP selected by the user
38
+ * @param redirectUri The url to reach to complete the user authorization which is the custom URL scheme that the Wallet Instance is registered to handle, usually a custom URL or deeplink
39
+ * @throws {AuthorizationError} if an error occurs during the authorization process
40
+ * @throws {AuthorizationIdpError} if an error occurs during the authorization process and the error is related to the IDP
41
+ * @returns the authorization response which contains code, state and iss
42
+ */
43
+ export const completeUserAuthorizationWithQueryMode: CompleteUserAuthorizationWithQueryMode =
44
+ async (
45
+ issuerRequestUri,
46
+ clientId,
47
+ issuerConf,
48
+ idpHint,
49
+ redirectUri,
50
+ authorizationContext
51
+ ) => {
52
+ /**
53
+ * Starts the authorization flow which dependes on the response mode and the request credential.
54
+ * If the response mode is "query" the authorization flow is handled differently via the authorization context which opens an in-app browser capable of catching the redirectSchema.
55
+ * The form_post.jwt mode is not currently supported.
56
+ */
57
+ const authzRequestEndpoint =
58
+ issuerConf.oauth_authorization_server.authorization_endpoint;
59
+ const params = new URLSearchParams({
60
+ client_id: clientId,
61
+ request_uri: issuerRequestUri,
62
+ idphint: idpHint,
63
+ });
64
+ const authUrl = `${authzRequestEndpoint}?${params}`;
65
+ var authRedirectUrl: string | undefined;
66
+
67
+ if (authorizationContext) {
68
+ const redirectSchema = new URL(redirectUri).protocol.replace(":", "");
69
+ authRedirectUrl = await authorizationContext
70
+ .authorize(authUrl, redirectSchema)
71
+ .catch((e) => {
72
+ throw new AuthorizationError(e.message);
73
+ });
74
+ } else {
75
+ // handler for redirectUri
76
+ Linking.addEventListener("url", ({ url }) => {
77
+ if (url.includes(redirectUri)) {
78
+ authRedirectUrl = url;
79
+ }
80
+ });
81
+
82
+ const openAuthUrlInBrowser = Linking.openURL(authUrl);
83
+
84
+ /*
85
+ * Waits for 120 seconds for the identificationRedirectUrl variable to be set
86
+ * by the custom url handler. If the timeout is exceeded, throw an exception
87
+ */
88
+ const unitAuthRedirectIsNotUndefined = until(
89
+ () => authRedirectUrl !== undefined,
90
+ 120
91
+ );
92
+
93
+ await Promise.all([openAuthUrlInBrowser, unitAuthRedirectIsNotUndefined]);
94
+
95
+ if (authRedirectUrl === undefined) {
96
+ throw new AuthorizationError("Invalid authentication redirect url");
97
+ }
98
+ }
99
+
100
+ const urlParse = parseUrl(authRedirectUrl);
101
+ const authRes = AuthorizationResultShape.safeParse(urlParse.query);
102
+ if (!authRes.success) {
103
+ const authErr = AuthorizationErrorShape.safeParse(urlParse.query);
104
+ if (!authErr.success) {
105
+ throw new AuthorizationError(authRes.error.message); // an error occured while parsing the result and the error
106
+ }
107
+ throw new AuthorizationIdpError(
108
+ authErr.data.error,
109
+ authErr.data.error_description
110
+ );
111
+ }
112
+ return authRes.data;
113
+ };
114
+
115
+ // TODO: SIW-1120 implement generic credential issuance flow
116
+ export const completeUserAuthorizationWithFormPostJwtMode = () => {
117
+ throw new Error("Not implemented");
118
+ };
@@ -1,92 +1,117 @@
1
- import uuid from "react-native-uuid";
2
- import { withEphemeralKey } from "../../utils/crypto";
3
- import { createDPopToken } from "../../utils/dpop";
4
- import type { StartUserAuthorization } from "./03-start-user-authorization";
5
- import { hasStatus, type Out } from "../../utils/misc";
1
+ import { hasStatus, type Out } from "../../../src/utils/misc";
6
2
  import type { EvaluateIssuerTrust } from "./02-evaluate-issuer-trust";
3
+ import type { StartUserAuthorization } from "./03-start-user-authorization";
4
+ import { withEphemeralKey } from "../../../src/utils/crypto";
5
+ import { createDPopToken } from "../../../src/utils/dpop";
6
+ import uuid from "react-native-uuid";
7
+ import { createPopToken } from "../../../src/utils/pop";
8
+ import * as WalletInstanceAttestation from "../../wallet-instance-attestation";
9
+ import type { CryptoContext } from "@pagopa/io-react-native-jwt";
7
10
  import { ASSERTION_TYPE } from "./const";
8
- import type { CompleteUserAuthorization } from "./04-complete-user-authorization";
11
+ import { TokenResponse } from "./types";
12
+ import { ValidationFailed } from "../../../src/utils/errors";
13
+ import type { CompleteUserAuthorizationWithQueryMode } from "./04-complete-user-authorization";
9
14
 
10
15
  export type AuthorizeAccess = (
11
16
  issuerConf: Out<EvaluateIssuerTrust>["issuerConf"],
12
- code: Out<CompleteUserAuthorization>["code"],
17
+ code: Out<CompleteUserAuthorizationWithQueryMode>["code"],
18
+ redirectUri: string,
13
19
  clientId: Out<StartUserAuthorization>["clientId"],
20
+ codeVerifier: Out<StartUserAuthorization>["codeVerifier"],
14
21
  context: {
15
22
  walletInstanceAttestation: string;
16
- walletProviderBaseUrl: string;
17
23
  appFetch?: GlobalFetch["fetch"];
24
+ wiaCryptoContext: CryptoContext;
18
25
  }
19
- ) => Promise<{
20
- // The access token to grant access to the credential
21
- accessToken: string;
22
- // The nonce, to prevent reply attacks
23
- nonce: string;
24
- // Same as input
25
- clientId: string;
26
- }>;
26
+ ) => Promise<{ accessToken: TokenResponse; tokenRequestSignedDPop: string }>;
27
27
 
28
28
  /**
29
- * Obtain the access token to finally request the credential
30
- *
31
- * @param issuerConf The Issuer configuration
32
- * @param code The access code from the User authorization phase
33
- * @param clientId Identifies the current client across all the requests of the issuing flow
34
- * @param context.walletInstanceAttestation The Wallet Instance Attestation token
35
- * @param context.walletProviderBaseUrl The base url of the Wallet Provider
29
+ * Creates and sends the DPoP Proof JWT to be presented with the authorization code to the /token endpoint of the authorization server
30
+ * for requesting the issuance of an access token bound to the public key of the Wallet Instance contained within the DPoP.
31
+ * This enables the Wallet Instance to request a digital credential.
32
+ * The DPoP Proof JWT is generated according to the section 4.3 of the DPoP RFC 9449 specification.
33
+ * @param issuerConf The issuer configuration returned by {@link evaluateIssuerTrust}
34
+ * @param code The authorization code returned by {@link completeUserAuthorizationWithQueryMode} or {@link completeUserAuthorizationWithFormPost}
35
+ * @param redirectUri The redirect URI which is the custom URL scheme that the Wallet Instance is registered to handle
36
+ * @param clientId The client id returned by {@link startUserAuthorization}
37
+ * @param codeVerifier The code verifier returned by {@link startUserAuthorization}
38
+ * @param context.walletInstanceAttestation The Wallet Instance's attestation
39
+ * @param context.wiaCryptoContext The Wallet Instance's crypto context
36
40
  * @param context.appFetch (optional) fetch api implementation. Default: built-in fetch
37
- * @returns
41
+ * @throws {ValidationFailed} if an error occurs while parsing the token response
42
+ * @return The token response containing the access token along with the token request signed with DPoP which has to be used in the {@link obtainCredential} step.
38
43
  */
39
44
  export const authorizeAccess: AuthorizeAccess = async (
40
45
  issuerConf,
41
46
  code,
42
47
  clientId,
48
+ redirectUri,
49
+ codeVerifier,
43
50
  context
44
- ): Promise<{ accessToken: string; nonce: string; clientId: string }> => {
51
+ ) => {
45
52
  const {
46
53
  appFetch = fetch,
47
54
  walletInstanceAttestation,
48
- walletProviderBaseUrl,
55
+ wiaCryptoContext,
49
56
  } = context;
50
57
 
51
- const tokenUrl = issuerConf.openid_credential_issuer.token_endpoint;
58
+ const parEndpoint =
59
+ issuerConf.oauth_authorization_server.pushed_authorization_request_endpoint;
60
+ const parUrl = new URL(parEndpoint);
61
+ const aud = `${parUrl.protocol}//${parUrl.hostname}`;
62
+ const iss = WalletInstanceAttestation.decode(walletInstanceAttestation)
63
+ .payload.cnf.jwk.kid;
52
64
 
65
+ const tokenUrl = issuerConf.oauth_authorization_server.token_endpoint;
53
66
  // Use an ephemeral key to be destroyed after use
54
- const signedDPop = await withEphemeralKey((ephemeralContext) =>
55
- createDPopToken(
56
- {
57
- htm: "POST",
58
- htu: tokenUrl,
59
- jti: `${uuid.v4()}`,
60
- },
61
- ephemeralContext
62
- )
67
+ const tokenRequestSignedDPop = await withEphemeralKey(
68
+ async (ephimeralContext) => {
69
+ return await createDPopToken(
70
+ {
71
+ htm: "POST",
72
+ htu: tokenUrl,
73
+ jti: `${uuid.v4()}`,
74
+ },
75
+ ephimeralContext
76
+ );
77
+ }
78
+ );
79
+
80
+ const signedWiaPoP = await createPopToken(
81
+ {
82
+ jti: `${uuid.v4()}`,
83
+ aud,
84
+ iss,
85
+ },
86
+ wiaCryptoContext
63
87
  );
64
88
 
65
- const codeVerifier = `${uuid.v4()}`;
66
89
  const requestBody = {
67
- grant_type: "authorization code",
90
+ grant_type: "authorization_code",
68
91
  client_id: clientId,
69
92
  code,
93
+ redirect_uri: redirectUri,
70
94
  code_verifier: codeVerifier,
71
95
  client_assertion_type: ASSERTION_TYPE,
72
- client_assertion: walletInstanceAttestation,
73
- redirect_uri: walletProviderBaseUrl,
96
+ client_assertion: walletInstanceAttestation + "~" + signedWiaPoP,
74
97
  };
75
- var formBody = new URLSearchParams(requestBody);
76
98
 
77
- return appFetch(tokenUrl, {
99
+ const authorizationRequestFormBody = new URLSearchParams(requestBody);
100
+ const tokenRes = await appFetch(tokenUrl, {
78
101
  method: "POST",
79
102
  headers: {
80
103
  "Content-Type": "application/x-www-form-urlencoded",
81
- DPoP: signedDPop,
104
+ DPoP: tokenRequestSignedDPop,
82
105
  },
83
- body: formBody.toString(),
106
+ body: authorizationRequestFormBody.toString(),
84
107
  })
85
108
  .then(hasStatus(200))
86
109
  .then((res) => res.json())
87
- .then((body) => ({
88
- accessToken: body.access_token,
89
- nonce: body.c_nonce,
90
- clientId,
91
- }));
110
+ .then((body) => TokenResponse.safeParse(body));
111
+
112
+ if (!tokenRes.success) {
113
+ throw new ValidationFailed(tokenRes.error.message);
114
+ }
115
+
116
+ return { accessToken: tokenRes.data, tokenRequestSignedDPop };
92
117
  };