@pagopa/io-react-native-wallet 0.12.0 → 0.13.1

Sign up to get free protection for your applications and to get access to all the features.
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 +55 -82
  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 +55 -32
  14. package/lib/commonjs/credential/issuance/05-authorize-access.js.map +1 -1
  15. package/lib/commonjs/credential/issuance/06-obtain-credential.js +50 -77
  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 +55 -79
  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 +53 -32
  67. package/lib/module/credential/issuance/05-authorize-access.js.map +1 -1
  68. package/lib/module/credential/issuance/06-obtain-credential.js +49 -74
  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 +22 -17
  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 +21 -15
  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 +87 -92
  167. package/src/credential/issuance/04-complete-user-authorization.ts +114 -13
  168. package/src/credential/issuance/05-authorize-access.ts +73 -48
  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,50 @@
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 { generateRandomAlphaNumericString, type Out } from "../../utils/misc";
8
4
  import type { EvaluateIssuerTrust } from "./02-evaluate-issuer-trust";
5
+ import type { StartFlow } from "./01-start-flow";
6
+ import { AuthorizationDetail, makeParRequest } from "../../utils/par";
9
7
  import { ASSERTION_TYPE } from "./const";
10
8
 
9
+ export type StartUserAuthorization = (
10
+ issuerConf: Out<EvaluateIssuerTrust>["issuerConf"],
11
+ credentialType: Out<StartFlow>["credentialType"],
12
+ context: {
13
+ wiaCryptoContext: CryptoContext;
14
+ walletInstanceAttestation: string;
15
+ redirectUri: string;
16
+ appFetch?: GlobalFetch["fetch"];
17
+ }
18
+ ) => Promise<{
19
+ issuerRequestUri: string;
20
+ clientId: string;
21
+ codeVerifier: string;
22
+ credentialDefinition: AuthorizationDetail;
23
+ }>;
24
+
25
+ /**
26
+ * Ensures that the credential type requested is supported by the issuer and contained in the
27
+ * issuer configuration.
28
+ * @param issuerConf The issuer configuration returned by {@link evaluateIssuerTrust}
29
+ * @param credentialType The type of the credential to be requested returned by {@link startFlow}
30
+ * @param context.wiaCryptoContext The Wallet Instance's crypto context
31
+ * @param context.walletInstanceAttestation The Wallet Instance's attestation
32
+ * @param context.redirectUri The redirect URI which is the custom URL scheme that the Wallet Instance is registered to handle
33
+ * @param context.appFetch (optional) fetch api implementation. Default: built-in fetch
34
+ * @returns The credential definition to be used in the request which includes the format and the type and its type
35
+ */
11
36
  const selectCredentialDefinition = (
12
37
  issuerConf: Out<EvaluateIssuerTrust>["issuerConf"],
13
38
  credentialType: Out<StartFlow>["credentialType"]
14
39
  ): AuthorizationDetail => {
15
- const { credentials_supported } = issuerConf.openid_credential_issuer;
40
+ const credential_configurations_supported =
41
+ issuerConf.openid_credential_issuer.credential_configurations_supported;
16
42
 
17
- const [result] = credentials_supported
18
- .filter((e) => e.credential_definition.type.includes(credentialType))
43
+ const [result] = Object.keys(credential_configurations_supported)
44
+ .filter((e) => e.includes(credentialType))
19
45
  .map((e) => ({
20
- credential_definition: { type: credentialType },
21
- format: e.format,
46
+ credential_configuration_id: credentialType,
47
+ format: credential_configurations_supported[e]!.format,
22
48
  type: "openid_credential" as const,
23
49
  }));
24
50
 
@@ -28,69 +54,46 @@ const selectCredentialDefinition = (
28
54
  return result;
29
55
  };
30
56
 
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() });
57
+ /**
58
+ * Ensures that the response mode requested is supported by the issuer and contained in the issuer configuration.
59
+ * @param issuerConf The issuer configuration
60
+ * @param credentialType The type of the credential to be requested
61
+ * @returns The response mode to be used in the request, "query" for PersonIdentificationData and "form_post.jwt" for all other types.
62
+ */
63
+ const selectResponseMode = (
64
+ issuerConf: Out<EvaluateIssuerTrust>["issuerConf"],
65
+ credentialType: Out<StartFlow>["credentialType"]
66
+ ): ResponseMode => {
67
+ const responseModeSupported =
68
+ issuerConf.oauth_authorization_server.response_modes_supported;
54
69
 
55
- const [correct, wrong] = [
56
- CorrectShape.safeParse(payload),
57
- WrongShapeForPID.safeParse(payload),
58
- ];
70
+ const responseMode =
71
+ credentialType === "PersonIdentificationData" ? "query" : "form_post.jwt";
59
72
 
60
- if (correct.success) {
61
- return correct.data;
62
- } else if (wrong.success) {
63
- return { request_uri: "https://fake-request-uri" };
73
+ if (!responseModeSupported.includes(responseMode)) {
74
+ throw new Error(`No response mode support the type '${credentialType}'`);
64
75
  }
65
- throw correct.error;
66
- };
67
76
 
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 }>;
77
+ return responseMode;
78
+ };
79
79
 
80
80
  /**
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
81
+ * WARNING: This function must be called after {@link evaluateIssuerTrust} and {@link startFlow}. The next steam is {@link compeUserAuthorizationWithQueryMode} or {@link compeUserAuthorizationWithFormPostJwtMode}
82
+ * Creates and sends a PAR request to the /as/par endpoint of the authroization server.
83
+ * This starts the authentication flow to obtain an access token.
84
+ * This token enables the Wallet Instance to request a digital credential from the Credential Endpoint of the Credential Issuer.
85
+ * 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
86
+ * along with the WTE and its proof of possession (WTE-PoP).
87
+ * Additionally, it includes a request object, which is a signed JWT encapsulating the type of digital credential requested (authorization_details),
88
+ * the application session identifier on the Wallet Instance side (state),
89
+ * the method (query or form_post.jwt) by which the Authorization Server
90
+ * should transmit the Authorization Response containing the authorization code issued upon the end user's authentication (response_mode)
91
+ * to the Wallet Instance's Token Endpoint to obtain the Access Token, and the redirect_uri of the Wallet Instance where the Authorization Response
92
+ * should be delivered. The redirect is achived by using a custom URL scheme that the Wallet Instance is registered to handle.
93
+ * @param issuerConf The issuer configuration
94
+ * @param credentialType The type of the credential to be requested returned by {@link selectCredentialDefinition}
95
+ * @param ctx The context object containing the Wallet Instance's cryptographic context, the Wallet Instance's attestation, the redirect URI and the fetch implementation
96
+ * @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
97
  */
95
98
  export const startUserAuthorization: StartUserAuthorization = async (
96
99
  issuerConf,
@@ -100,39 +103,31 @@ export const startUserAuthorization: StartUserAuthorization = async (
100
103
  const {
101
104
  wiaCryptoContext,
102
105
  walletInstanceAttestation,
103
- walletProviderBaseUrl,
104
- additionalParams = {},
106
+ redirectUri,
105
107
  appFetch = fetch,
106
108
  } = ctx;
109
+
107
110
  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;
111
+ const codeVerifier = generateRandomAlphaNumericString(64);
112
+ const parEndpoint =
113
+ issuerConf.oauth_authorization_server.pushed_authorization_request_endpoint;
114
+ const credentialDefinition = selectCredentialDefinition(
115
+ issuerConf,
116
+ credentialType
117
+ );
118
+ const responseMode = selectResponseMode(issuerConf, credentialType);
119
+
112
120
  const getPar = makeParRequest({ wiaCryptoContext, appFetch });
113
121
  const issuerRequestUri = await getPar(
114
122
  clientId,
115
123
  codeVerifier,
116
- walletProviderBaseUrl,
117
- parUrl,
124
+ redirectUri,
125
+ responseMode,
126
+ parEndpoint,
118
127
  walletInstanceAttestation,
119
- [selectCredentialDefinition(issuerConf, credentialType)],
128
+ [credentialDefinition],
120
129
  ASSERTION_TYPE
121
130
  );
122
131
 
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 };
132
+ return { issuerRequestUri, clientId, codeVerifier, credentialDefinition };
138
133
  };
@@ -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 "../../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
1
  import { hasStatus, type Out } from "../../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 "../../utils/crypto";
5
+ import { createDPopToken } from "../../utils/dpop";
6
+ import uuid from "react-native-uuid";
7
+ import { createPopToken } from "../../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 "../../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
  };