@pagopa/io-react-native-wallet 0.24.1 → 0.26.0
Sign up to get free protection for your applications and to get access to all the features.
- package/README.md +0 -32
- package/lib/commonjs/client/generated/wallet-provider.js +39 -16
- package/lib/commonjs/client/generated/wallet-provider.js.map +1 -1
- package/lib/commonjs/client/index.js +25 -10
- package/lib/commonjs/client/index.js.map +1 -1
- package/lib/commonjs/credential/issuance/03-start-user-authorization.js +2 -2
- package/lib/commonjs/credential/issuance/04-complete-user-authorization.js +36 -67
- package/lib/commonjs/credential/issuance/04-complete-user-authorization.js.map +1 -1
- package/lib/commonjs/credential/issuance/05-authorize-access.js +5 -2
- package/lib/commonjs/credential/issuance/05-authorize-access.js.map +1 -1
- package/lib/commonjs/credential/issuance/06-obtain-credential.js +26 -17
- package/lib/commonjs/credential/issuance/06-obtain-credential.js.map +1 -1
- package/lib/commonjs/credential/issuance/README.md +8 -14
- package/lib/commonjs/credential/issuance/errors.js +52 -0
- package/lib/commonjs/credential/issuance/errors.js.map +1 -0
- package/lib/commonjs/credential/issuance/index.js +13 -2
- package/lib/commonjs/credential/issuance/index.js.map +1 -1
- package/lib/commonjs/credential/issuance/types.js +1 -5
- package/lib/commonjs/credential/issuance/types.js.map +1 -1
- package/lib/commonjs/credential/presentation/01-start-flow.js +1 -1
- package/lib/commonjs/credential/presentation/01-start-flow.js.map +1 -1
- package/lib/commonjs/credential/presentation/03-get-request-object.js +2 -2
- package/lib/commonjs/credential/presentation/03-get-request-object.js.map +1 -1
- package/lib/commonjs/credential/presentation/04-send-authorization-response.js +2 -2
- package/lib/commonjs/credential/presentation/04-send-authorization-response.js.map +1 -1
- package/lib/commonjs/credential/presentation/errors.js +49 -0
- package/lib/commonjs/credential/presentation/errors.js.map +1 -0
- package/lib/commonjs/credential/presentation/index.js +5 -0
- package/lib/commonjs/credential/presentation/index.js.map +1 -1
- package/lib/commonjs/credential/status/02-status-attestation.js +8 -6
- package/lib/commonjs/credential/status/02-status-attestation.js.map +1 -1
- package/lib/commonjs/credential/status/README.md +5 -2
- package/lib/commonjs/credential/status/types.js +1 -14
- package/lib/commonjs/credential/status/types.js.map +1 -1
- package/lib/commonjs/sd-jwt/errors.js +40 -0
- package/lib/commonjs/sd-jwt/errors.js.map +1 -0
- package/lib/commonjs/sd-jwt/index.js +8 -4
- package/lib/commonjs/sd-jwt/index.js.map +1 -1
- package/lib/commonjs/sd-jwt/verifier.js +5 -1
- package/lib/commonjs/sd-jwt/verifier.js.map +1 -1
- package/lib/commonjs/trust/index.js +2 -2
- package/lib/commonjs/trust/index.js.map +1 -1
- package/lib/commonjs/utils/decoder.js +3 -1
- package/lib/commonjs/utils/decoder.js.map +1 -1
- package/lib/commonjs/utils/error-codes.js +51 -0
- package/lib/commonjs/utils/error-codes.js.map +1 -0
- package/lib/commonjs/utils/errors.js +119 -463
- package/lib/commonjs/utils/errors.js.map +1 -1
- package/lib/commonjs/utils/misc.js +23 -55
- package/lib/commonjs/utils/misc.js.map +1 -1
- package/lib/commonjs/utils/par.js +2 -1
- package/lib/commonjs/utils/par.js.map +1 -1
- package/lib/commonjs/wallet-instance/README.md +26 -5
- package/lib/commonjs/wallet-instance/index.js +33 -7
- package/lib/commonjs/wallet-instance/index.js.map +1 -1
- package/lib/commonjs/wallet-instance-attestation/README.md +8 -2
- package/lib/commonjs/wallet-instance-attestation/issuing.js +13 -10
- package/lib/commonjs/wallet-instance-attestation/issuing.js.map +1 -1
- package/lib/module/client/generated/wallet-provider.js +31 -11
- package/lib/module/client/generated/wallet-provider.js.map +1 -1
- package/lib/module/client/index.js +22 -8
- package/lib/module/client/index.js.map +1 -1
- package/lib/module/credential/issuance/03-start-user-authorization.js +2 -2
- package/lib/module/credential/issuance/04-complete-user-authorization.js +33 -65
- package/lib/module/credential/issuance/04-complete-user-authorization.js.map +1 -1
- package/lib/module/credential/issuance/05-authorize-access.js +7 -4
- package/lib/module/credential/issuance/05-authorize-access.js.map +1 -1
- package/lib/module/credential/issuance/06-obtain-credential.js +29 -20
- package/lib/module/credential/issuance/06-obtain-credential.js.map +1 -1
- package/lib/module/credential/issuance/README.md +8 -14
- package/lib/module/credential/issuance/errors.js +44 -0
- package/lib/module/credential/issuance/errors.js.map +1 -0
- package/lib/module/credential/issuance/index.js +3 -2
- package/lib/module/credential/issuance/index.js.map +1 -1
- package/lib/module/credential/issuance/types.js +0 -3
- package/lib/module/credential/issuance/types.js.map +1 -1
- package/lib/module/credential/presentation/01-start-flow.js +1 -1
- package/lib/module/credential/presentation/01-start-flow.js.map +1 -1
- package/lib/module/credential/presentation/03-get-request-object.js +3 -3
- package/lib/module/credential/presentation/03-get-request-object.js.map +1 -1
- package/lib/module/credential/presentation/04-send-authorization-response.js +3 -3
- package/lib/module/credential/presentation/04-send-authorization-response.js.map +1 -1
- package/lib/module/credential/presentation/errors.js +42 -0
- package/lib/module/credential/presentation/errors.js.map +1 -0
- package/lib/module/credential/presentation/index.js +2 -1
- package/lib/module/credential/presentation/index.js.map +1 -1
- package/lib/module/credential/status/02-status-attestation.js +11 -9
- package/lib/module/credential/status/02-status-attestation.js.map +1 -1
- package/lib/module/credential/status/README.md +5 -2
- package/lib/module/credential/status/types.js +0 -12
- package/lib/module/credential/status/types.js.map +1 -1
- package/lib/module/sd-jwt/errors.js +32 -0
- package/lib/module/sd-jwt/errors.js.map +1 -0
- package/lib/module/sd-jwt/index.js +5 -5
- package/lib/module/sd-jwt/index.js.map +1 -1
- package/lib/module/sd-jwt/verifier.js +5 -1
- package/lib/module/sd-jwt/verifier.js.map +1 -1
- package/lib/module/trust/index.js +3 -3
- package/lib/module/trust/index.js.map +1 -1
- package/lib/module/utils/decoder.js +3 -1
- package/lib/module/utils/decoder.js.map +1 -1
- package/lib/module/utils/error-codes.js +43 -0
- package/lib/module/utils/error-codes.js.map +1 -0
- package/lib/module/utils/errors.js +98 -438
- package/lib/module/utils/errors.js.map +1 -1
- package/lib/module/utils/misc.js +19 -49
- package/lib/module/utils/misc.js.map +1 -1
- package/lib/module/utils/par.js +3 -2
- package/lib/module/utils/par.js.map +1 -1
- package/lib/module/wallet-instance/README.md +26 -5
- package/lib/module/wallet-instance/index.js +32 -7
- package/lib/module/wallet-instance/index.js.map +1 -1
- package/lib/module/wallet-instance-attestation/README.md +8 -2
- package/lib/module/wallet-instance-attestation/issuing.js +15 -12
- package/lib/module/wallet-instance-attestation/issuing.js.map +1 -1
- package/lib/typescript/client/generated/wallet-provider.d.ts +138 -27
- package/lib/typescript/client/generated/wallet-provider.d.ts.map +1 -1
- package/lib/typescript/client/index.d.ts +7 -1
- package/lib/typescript/client/index.d.ts.map +1 -1
- package/lib/typescript/credential/issuance/03-start-user-authorization.d.ts +2 -2
- package/lib/typescript/credential/issuance/04-complete-user-authorization.d.ts +17 -16
- package/lib/typescript/credential/issuance/04-complete-user-authorization.d.ts.map +1 -1
- package/lib/typescript/credential/issuance/05-authorize-access.d.ts.map +1 -1
- package/lib/typescript/credential/issuance/06-obtain-credential.d.ts.map +1 -1
- package/lib/typescript/credential/issuance/errors.d.ts +28 -0
- package/lib/typescript/credential/issuance/errors.d.ts.map +1 -0
- package/lib/typescript/credential/issuance/index.d.ts +4 -3
- package/lib/typescript/credential/issuance/index.d.ts.map +1 -1
- package/lib/typescript/credential/issuance/types.d.ts +0 -8
- package/lib/typescript/credential/issuance/types.d.ts.map +1 -1
- package/lib/typescript/credential/presentation/03-get-request-object.d.ts.map +1 -1
- package/lib/typescript/credential/presentation/04-send-authorization-response.d.ts.map +1 -1
- package/lib/typescript/credential/presentation/errors.d.ts +25 -0
- package/lib/typescript/credential/presentation/errors.d.ts.map +1 -0
- package/lib/typescript/credential/presentation/index.d.ts +2 -1
- package/lib/typescript/credential/presentation/index.d.ts.map +1 -1
- package/lib/typescript/credential/status/02-status-attestation.d.ts.map +1 -1
- package/lib/typescript/credential/status/types.d.ts +0 -15
- package/lib/typescript/credential/status/types.d.ts.map +1 -1
- package/lib/typescript/sd-jwt/errors.d.ts +20 -0
- package/lib/typescript/sd-jwt/errors.d.ts.map +1 -0
- package/lib/typescript/sd-jwt/index.d.ts +3 -2
- package/lib/typescript/sd-jwt/index.d.ts.map +1 -1
- package/lib/typescript/utils/error-codes.d.ts +45 -0
- package/lib/typescript/utils/error-codes.d.ts.map +1 -0
- package/lib/typescript/utils/errors.d.ts +88 -225
- package/lib/typescript/utils/errors.d.ts.map +1 -1
- package/lib/typescript/utils/misc.d.ts +9 -24
- package/lib/typescript/utils/misc.d.ts.map +1 -1
- package/lib/typescript/utils/par.d.ts.map +1 -1
- package/lib/typescript/wallet-instance/index.d.ts +17 -1
- package/lib/typescript/wallet-instance/index.d.ts.map +1 -1
- package/lib/typescript/wallet-instance-attestation/issuing.d.ts.map +1 -1
- package/lib/typescript/wallet-instance-attestation/types.d.ts +4 -4
- package/package.json +1 -1
- package/src/client/generated/wallet-provider.ts +43 -13
- package/src/client/index.ts +28 -15
- package/src/credential/issuance/03-start-user-authorization.ts +2 -2
- package/src/credential/issuance/04-complete-user-authorization.ts +57 -118
- package/src/credential/issuance/05-authorize-access.ts +7 -4
- package/src/credential/issuance/06-obtain-credential.ts +39 -39
- package/src/credential/issuance/README.md +8 -14
- package/src/credential/issuance/errors.ts +44 -0
- package/src/credential/issuance/index.ts +8 -2
- package/src/credential/issuance/types.ts +0 -8
- package/src/credential/presentation/01-start-flow.ts +1 -1
- package/src/credential/presentation/03-get-request-object.ts +3 -3
- package/src/credential/presentation/04-send-authorization-response.ts +3 -3
- package/src/credential/presentation/errors.ts +41 -0
- package/src/credential/presentation/index.ts +2 -0
- package/src/credential/status/02-status-attestation.ts +17 -25
- package/src/credential/status/README.md +5 -2
- package/src/credential/status/types.ts +0 -15
- package/src/sd-jwt/errors.ts +39 -0
- package/src/sd-jwt/index.ts +5 -8
- package/src/sd-jwt/verifier.ts +5 -5
- package/src/trust/index.ts +3 -3
- package/src/utils/decoder.ts +3 -3
- package/src/utils/error-codes.ts +50 -0
- package/src/utils/errors.ts +152 -476
- package/src/utils/misc.ts +21 -65
- package/src/utils/par.ts +3 -2
- package/src/wallet-instance/README.md +26 -5
- package/src/wallet-instance/index.ts +40 -18
- package/src/wallet-instance-attestation/README.md +8 -2
- package/src/wallet-instance-attestation/issuing.ts +28 -36
package/src/client/index.ts
CHANGED
@@ -1,12 +1,16 @@
|
|
1
|
+
import { parseRawHttpResponse } from "../utils/misc";
|
1
2
|
import { WalletProviderResponseError } from "../utils/errors";
|
2
3
|
import {
|
3
4
|
ProblemDetail,
|
4
5
|
createApiClient as createWalletProviderApiClient,
|
6
|
+
ApiClient as WalletProviderApiClient,
|
7
|
+
type EndpointParameters,
|
5
8
|
} from "./generated/wallet-provider";
|
6
|
-
import { ApiClient as WalletProviderApiClient } from "./generated/wallet-provider";
|
7
9
|
|
8
10
|
export type WalletProviderClient = WalletProviderApiClient;
|
9
11
|
|
12
|
+
type RawHttpResponse = Awaited<ReturnType<typeof parseRawHttpResponse>>;
|
13
|
+
|
10
14
|
const validateResponse = async (response: Response) => {
|
11
15
|
if (!response.ok) {
|
12
16
|
let problemDetail: ProblemDetail = {};
|
@@ -18,12 +22,11 @@ const validateResponse = async (response: Response) => {
|
|
18
22
|
};
|
19
23
|
}
|
20
24
|
|
21
|
-
throw new WalletProviderResponseError(
|
22
|
-
problemDetail.title ?? "Invalid response from Wallet Provider",
|
23
|
-
problemDetail
|
24
|
-
|
25
|
-
|
26
|
-
);
|
25
|
+
throw new WalletProviderResponseError({
|
26
|
+
message: problemDetail.title ?? "Invalid response from Wallet Provider",
|
27
|
+
reason: problemDetail,
|
28
|
+
statusCode: response.status,
|
29
|
+
});
|
27
30
|
}
|
28
31
|
return response;
|
29
32
|
};
|
@@ -36,7 +39,7 @@ export const getWalletProviderClient = (context: {
|
|
36
39
|
|
37
40
|
return createWalletProviderApiClient(
|
38
41
|
(method, url, params) =>
|
39
|
-
appFetch(url, {
|
42
|
+
appFetch(interpolateUrl(url, params), {
|
40
43
|
method,
|
41
44
|
body: params ? JSON.stringify(params.body) : undefined,
|
42
45
|
headers: {
|
@@ -44,13 +47,23 @@ export const getWalletProviderClient = (context: {
|
|
44
47
|
},
|
45
48
|
})
|
46
49
|
.then(validateResponse)
|
47
|
-
.then(
|
48
|
-
const contentType = res.headers.get("content-type");
|
49
|
-
if (contentType?.includes("application/json")) {
|
50
|
-
return res.json();
|
51
|
-
}
|
52
|
-
return res.text();
|
53
|
-
}),
|
50
|
+
.then<RawHttpResponse>(parseRawHttpResponse),
|
54
51
|
walletProviderBaseUrl
|
55
52
|
);
|
56
53
|
};
|
54
|
+
|
55
|
+
/**
|
56
|
+
* Function to interpolate the url when the request includes path params.
|
57
|
+
* The client generator expects the literal name of the param in the url
|
58
|
+
* and passes the actual values in a separate object.
|
59
|
+
*/
|
60
|
+
export const interpolateUrl = (url: string, params?: EndpointParameters) => {
|
61
|
+
if (!params?.path) return url;
|
62
|
+
|
63
|
+
for (const [key, value] of Object.entries(params.path)) {
|
64
|
+
if (typeof value === "string") {
|
65
|
+
url = url.replace(`{${key}}`, value);
|
66
|
+
}
|
67
|
+
}
|
68
|
+
return url;
|
69
|
+
};
|
@@ -79,7 +79,7 @@ const selectResponseMode = (
|
|
79
79
|
|
80
80
|
/**
|
81
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
|
82
|
+
* Creates and sends a PAR request to the /as/par endpoint of the authorization server.
|
83
83
|
* This starts the authentication flow to obtain an access token.
|
84
84
|
* This token enables the Wallet Instance to request a digital credential from the Credential Endpoint of the Credential Issuer.
|
85
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
|
@@ -88,7 +88,7 @@ const selectResponseMode = (
|
|
88
88
|
* the application session identifier on the Wallet Instance side (state),
|
89
89
|
* the method (query or form_post.jwt) by which the Authorization Server
|
90
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
|
91
|
+
* to the Wallet Instance's Token Endpoint to obtain the Access Token, and the redirectUri of the Wallet Instance where the Authorization Response
|
92
92
|
* should be delivered. The redirect is achived by using a custom URL scheme that the Wallet Instance is registered to handle.
|
93
93
|
* @param issuerConf The issuer configuration
|
94
94
|
* @param credentialType The type of the credential to be requested returned by {@link selectCredentialDefinition}
|
@@ -1,26 +1,13 @@
|
|
1
1
|
import {
|
2
2
|
AuthorizationErrorShape,
|
3
3
|
AuthorizationResultShape,
|
4
|
-
type AuthorizationContext,
|
5
4
|
type AuthorizationResult,
|
6
5
|
} from "../../utils/auth";
|
7
|
-
import {
|
8
|
-
createAbortPromiseFromSignal,
|
9
|
-
hasStatus,
|
10
|
-
isDefined,
|
11
|
-
until,
|
12
|
-
type Out,
|
13
|
-
} from "../../utils/misc";
|
6
|
+
import { hasStatusOrThrow, type Out } from "../../utils/misc";
|
14
7
|
import type { StartUserAuthorization } from "./03-start-user-authorization";
|
15
8
|
import parseUrl from "parse-url";
|
16
|
-
import {
|
17
|
-
AuthorizationError,
|
18
|
-
AuthorizationIdpError,
|
19
|
-
OperationAbortedError,
|
20
|
-
ValidationFailed,
|
21
|
-
} from "../../utils/errors";
|
9
|
+
import { IssuerResponseError, ValidationFailed } from "../../utils/errors";
|
22
10
|
import type { EvaluateIssuerTrust } from "./02-evaluate-issuer-trust";
|
23
|
-
import { Linking } from "react-native";
|
24
11
|
import {
|
25
12
|
decode,
|
26
13
|
encodeBase64,
|
@@ -31,18 +18,13 @@ import { RequestObject } from "../presentation/types";
|
|
31
18
|
import uuid from "react-native-uuid";
|
32
19
|
import { ResponseUriResultShape } from "./types";
|
33
20
|
import { getJwtFromFormPost } from "../../utils/decoder";
|
21
|
+
import { AuthorizationError, AuthorizationIdpError } from "./errors";
|
34
22
|
|
35
23
|
/**
|
36
24
|
* 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.
|
37
25
|
*/
|
38
26
|
export type CompleteUserAuthorizationWithQueryMode = (
|
39
|
-
|
40
|
-
clientId: Out<StartUserAuthorization>["clientId"],
|
41
|
-
issuerConf: Out<EvaluateIssuerTrust>["issuerConf"],
|
42
|
-
idpHint: string,
|
43
|
-
redirectUri: string,
|
44
|
-
authorizationContext?: AuthorizationContext,
|
45
|
-
signal?: AbortSignal
|
27
|
+
authRedirectUrl: string
|
46
28
|
) => Promise<AuthorizationResult>;
|
47
29
|
|
48
30
|
export type CompleteUserAuthorizationWithFormPostJwtMode = (
|
@@ -63,99 +45,56 @@ export type GetRequestedCredentialToBePresented = (
|
|
63
45
|
appFetch?: GlobalFetch["fetch"]
|
64
46
|
) => Promise<RequestObject>;
|
65
47
|
|
48
|
+
export type BuildAuthorizationUrl = (
|
49
|
+
issuerRequestUri: Out<StartUserAuthorization>["issuerRequestUri"],
|
50
|
+
clientId: Out<StartUserAuthorization>["clientId"],
|
51
|
+
issuerConf: Out<EvaluateIssuerTrust>["issuerConf"],
|
52
|
+
idpHint: string
|
53
|
+
) => Promise<{
|
54
|
+
authUrl: string;
|
55
|
+
}>;
|
56
|
+
|
66
57
|
/**
|
67
|
-
* WARNING: This function must be called after {@link startUserAuthorization}. The
|
68
|
-
*
|
69
|
-
* It is used to complete the user authorization by catching the redirectSchema from the authorization server which then contains the authorization response.
|
70
|
-
* 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.
|
71
|
-
* If the 302 redirect happens and the redirectSchema is caught, the function will return the authorization response after parsing it from the query string.
|
58
|
+
* WARNING: This function must be called after {@link startUserAuthorization}. The generated authUrl must be used to open a browser or webview capable of catching the redirectSchema to perform a get request to the authorization endpoint.
|
59
|
+
* Builds the authorization URL to which the end user should be redirected to continue the authentication flow.
|
72
60
|
* @param issuerRequestUri the URI of the issuer where the request is sent
|
73
61
|
* @param clientId Identifies the current client across all the requests of the issuing flow returned by {@link startUserAuthorization}
|
74
62
|
* @param issuerConf The issuer configuration returned by {@link evaluateIssuerTrust}
|
75
|
-
* @param
|
76
|
-
*
|
77
|
-
* @param idphint Unique identifier of the SPID IDP selected by the user
|
78
|
-
* @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
|
79
|
-
* @param signal An optional {@link AbortSignal} to abort the operation when using the default browser
|
80
|
-
* @throws {AuthorizationError} if an error occurs during the authorization process
|
81
|
-
* @throws {AuthorizationIdpError} if an error occurs during the authorization process and the error is related to the IDP
|
82
|
-
* @throws {OperationAbortedError} if the caller aborts the operation via the provided signal
|
83
|
-
* @returns the authorization response which contains code, state and iss
|
63
|
+
* @param idpHint Unique identifier of the IDP selected by the user
|
64
|
+
* @returns An object containing the authorization URL
|
84
65
|
*/
|
85
|
-
export const
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
signal
|
94
|
-
) => {
|
95
|
-
const authzRequestEndpoint =
|
96
|
-
issuerConf.oauth_authorization_server.authorization_endpoint;
|
97
|
-
const params = new URLSearchParams({
|
98
|
-
client_id: clientId,
|
99
|
-
request_uri: issuerRequestUri,
|
100
|
-
idphint: idpHint,
|
101
|
-
});
|
102
|
-
const authUrl = `${authzRequestEndpoint}?${params}`;
|
103
|
-
var authRedirectUrl: string | undefined;
|
104
|
-
|
105
|
-
if (authorizationContext) {
|
106
|
-
const redirectSchema = new URL(redirectUri).protocol.replace(":", "");
|
107
|
-
authRedirectUrl = await authorizationContext
|
108
|
-
.authorize(authUrl, redirectSchema)
|
109
|
-
.catch((e) => {
|
110
|
-
throw new AuthorizationError(e.message);
|
111
|
-
});
|
112
|
-
} else {
|
113
|
-
// handler for redirectUri
|
114
|
-
const urlEventListener = Linking.addEventListener("url", ({ url }) => {
|
115
|
-
if (url.includes(redirectUri)) {
|
116
|
-
authRedirectUrl = url;
|
117
|
-
}
|
118
|
-
});
|
66
|
+
export const buildAuthorizationUrl: BuildAuthorizationUrl = async (
|
67
|
+
issuerRequestUri,
|
68
|
+
clientId,
|
69
|
+
issuerConf,
|
70
|
+
idpHint
|
71
|
+
) => {
|
72
|
+
const authzRequestEndpoint =
|
73
|
+
issuerConf.oauth_authorization_server.authorization_endpoint;
|
119
74
|
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
75
|
+
const params = new URLSearchParams({
|
76
|
+
client_id: clientId,
|
77
|
+
request_uri: issuerRequestUri,
|
78
|
+
idphint: idpHint,
|
79
|
+
});
|
124
80
|
|
125
|
-
|
126
|
-
* Waits for 120 seconds for the identificationRedirectUrl variable to be set
|
127
|
-
* by the custom url handler. If the timeout is exceeded, throw an exception
|
128
|
-
*/
|
129
|
-
const unitAuthRedirectIsNotUndefined = until(
|
130
|
-
() => authRedirectUrl !== undefined,
|
131
|
-
120
|
132
|
-
);
|
81
|
+
const authUrl = `${authzRequestEndpoint}?${params}`;
|
133
82
|
|
134
|
-
|
135
|
-
|
136
|
-
* The first event that occurs will resolve the promise.
|
137
|
-
* This is useful to properly cleanup when the caller aborts this operation.
|
138
|
-
*/
|
139
|
-
const winner = await Promise.race(
|
140
|
-
[operationIsAborted?.listen(), unitAuthRedirectIsNotUndefined].filter(
|
141
|
-
isDefined
|
142
|
-
)
|
143
|
-
).finally(() => {
|
144
|
-
urlEventListener.remove();
|
145
|
-
operationIsAborted?.remove();
|
146
|
-
});
|
147
|
-
|
148
|
-
if (winner === "OPERATION_ABORTED") {
|
149
|
-
throw new OperationAbortedError("DefaultQueryModeAuthorization");
|
150
|
-
}
|
151
|
-
|
152
|
-
if (authRedirectUrl === undefined) {
|
153
|
-
throw new AuthorizationError("Invalid authentication redirect url");
|
154
|
-
}
|
155
|
-
}
|
83
|
+
return { authUrl };
|
84
|
+
};
|
156
85
|
|
86
|
+
/**
|
87
|
+
* WARNING: This function must be called after obtaining the authorization redirect URL from the webviews (SPID and CIE L3) or browser for CIEID.
|
88
|
+
* Complete User authorization via strong identification when the response mode is "query" and the request credential is a PersonIdentificationData.
|
89
|
+
* This function parses the authorization redirect URL to extract the authorization response.
|
90
|
+
* @param authRedirectUrl The URL to which the end user should be redirected to start the authentication flow
|
91
|
+
* @returns the authorization response which contains code, state and iss
|
92
|
+
*/
|
93
|
+
export const completeUserAuthorizationWithQueryMode: CompleteUserAuthorizationWithQueryMode =
|
94
|
+
async (authRedirectUrl) => {
|
157
95
|
const query = parseUrl(authRedirectUrl).query;
|
158
|
-
|
96
|
+
|
97
|
+
return parseAuthorizationResponse(query);
|
159
98
|
};
|
160
99
|
|
161
100
|
/**
|
@@ -183,16 +122,16 @@ export const getRequestedCredentialToBePresented: GetRequestedCredentialToBePres
|
|
183
122
|
`${authzRequestEndpoint}?${params.toString()}`,
|
184
123
|
{ method: "GET" }
|
185
124
|
)
|
186
|
-
.then(
|
125
|
+
.then(hasStatusOrThrow(200, IssuerResponseError))
|
187
126
|
.then((res) => res.text())
|
188
127
|
.then((jws) => decode(jws))
|
189
128
|
.then((reqObj) => RequestObject.safeParse(reqObj.payload));
|
190
129
|
|
191
130
|
if (!requestObject.success) {
|
192
|
-
throw new ValidationFailed(
|
193
|
-
"Request Object validation failed",
|
194
|
-
requestObject.error.message
|
195
|
-
);
|
131
|
+
throw new ValidationFailed({
|
132
|
+
message: "Request Object validation failed",
|
133
|
+
reason: requestObject.error.message,
|
134
|
+
});
|
196
135
|
}
|
197
136
|
return requestObject.data;
|
198
137
|
};
|
@@ -300,22 +239,22 @@ export const completeUserAuthorizationWithFormPostJwtMode: CompleteUserAuthoriza
|
|
300
239
|
},
|
301
240
|
body,
|
302
241
|
})
|
303
|
-
.then(
|
242
|
+
.then(hasStatusOrThrow(200, IssuerResponseError))
|
304
243
|
.then((reqUri) => reqUri.json());
|
305
244
|
|
306
245
|
const responseUri = ResponseUriResultShape.safeParse(resUriRes);
|
307
246
|
if (!responseUri.success) {
|
308
|
-
throw new ValidationFailed(
|
309
|
-
"Response Uri validation failed",
|
310
|
-
responseUri.error.message
|
311
|
-
);
|
247
|
+
throw new ValidationFailed({
|
248
|
+
message: "Response Uri validation failed",
|
249
|
+
reason: responseUri.error.message,
|
250
|
+
});
|
312
251
|
}
|
313
252
|
|
314
253
|
return await appFetch(responseUri.data.redirect_uri)
|
315
|
-
.then(
|
254
|
+
.then(hasStatusOrThrow(200, IssuerResponseError))
|
316
255
|
.then((res) => res.text())
|
317
256
|
.then(getJwtFromFormPost)
|
318
|
-
.then((cbRes) =>
|
257
|
+
.then((cbRes) => parseAuthorizationResponse(cbRes.decodedJwt.payload));
|
319
258
|
};
|
320
259
|
|
321
260
|
/**
|
@@ -325,7 +264,7 @@ export const completeUserAuthorizationWithFormPostJwtMode: CompleteUserAuthoriza
|
|
325
264
|
* @param authRes the authorization response to be parsed
|
326
265
|
* @returns the authorization result which contains code, state and iss
|
327
266
|
*/
|
328
|
-
export const
|
267
|
+
export const parseAuthorizationResponse = (
|
329
268
|
authRes: unknown
|
330
269
|
): AuthorizationResult => {
|
331
270
|
const authResParsed = AuthorizationResultShape.safeParse(authRes);
|
@@ -1,4 +1,4 @@
|
|
1
|
-
import {
|
1
|
+
import { hasStatusOrThrow, type Out } from "../../utils/misc";
|
2
2
|
import type { EvaluateIssuerTrust } from "./02-evaluate-issuer-trust";
|
3
3
|
import type { StartUserAuthorization } from "./03-start-user-authorization";
|
4
4
|
import { createDPopToken } from "../../utils/dpop";
|
@@ -8,7 +8,7 @@ import * as WalletInstanceAttestation from "../../wallet-instance-attestation";
|
|
8
8
|
import type { CryptoContext } from "@pagopa/io-react-native-jwt";
|
9
9
|
import { ASSERTION_TYPE } from "./const";
|
10
10
|
import { TokenResponse } from "./types";
|
11
|
-
import { ValidationFailed } from "../../utils/errors";
|
11
|
+
import { IssuerResponseError, ValidationFailed } from "../../utils/errors";
|
12
12
|
import type { CompleteUserAuthorizationWithQueryMode } from "./04-complete-user-authorization";
|
13
13
|
|
14
14
|
export type AuthorizeAccess = (
|
@@ -103,12 +103,15 @@ export const authorizeAccess: AuthorizeAccess = async (
|
|
103
103
|
},
|
104
104
|
body: authorizationRequestFormBody.toString(),
|
105
105
|
})
|
106
|
-
.then(
|
106
|
+
.then(hasStatusOrThrow(200, IssuerResponseError))
|
107
107
|
.then((res) => res.json())
|
108
108
|
.then((body) => TokenResponse.safeParse(body));
|
109
109
|
|
110
110
|
if (!tokenRes.success) {
|
111
|
-
throw new ValidationFailed(
|
111
|
+
throw new ValidationFailed({
|
112
|
+
message: "Token Response validation failed",
|
113
|
+
reason: tokenRes.error.message,
|
114
|
+
});
|
112
115
|
}
|
113
116
|
|
114
117
|
return { accessToken: tokenRes.data };
|
@@ -1,21 +1,20 @@
|
|
1
1
|
import {
|
2
|
+
type CryptoContext,
|
2
3
|
sha256ToBase64,
|
3
4
|
SignJWT,
|
4
|
-
type CryptoContext,
|
5
5
|
} from "@pagopa/io-react-native-jwt";
|
6
6
|
import type { AuthorizeAccess } from "./05-authorize-access";
|
7
7
|
import type { EvaluateIssuerTrust } from "./02-evaluate-issuer-trust";
|
8
|
-
import {
|
8
|
+
import { hasStatusOrThrow, type Out } from "../../utils/misc";
|
9
9
|
import type { StartUserAuthorization } from "./03-start-user-authorization";
|
10
10
|
import {
|
11
|
-
|
12
|
-
|
13
|
-
|
11
|
+
IssuerResponseError,
|
12
|
+
IssuerResponseErrorCodes,
|
13
|
+
ResponseErrorBuilder,
|
14
14
|
UnexpectedStatusCodeError,
|
15
15
|
ValidationFailed,
|
16
16
|
} from "../../utils/errors";
|
17
|
-
import {
|
18
|
-
|
17
|
+
import { CredentialResponse } from "./types";
|
19
18
|
import { createDPopToken } from "../../utils/dpop";
|
20
19
|
import uuid from "react-native-uuid";
|
21
20
|
|
@@ -97,7 +96,7 @@ export const obtainCredential: ObtainCredential = async (
|
|
97
96
|
);
|
98
97
|
|
99
98
|
// Validation of accessTokenResponse.authorization_details if contain credentialDefinition
|
100
|
-
const
|
99
|
+
const containsCredentialDefinition = accessToken.authorization_details.some(
|
101
100
|
(c) =>
|
102
101
|
c.credential_configuration_id ===
|
103
102
|
credentialDefinition.credential_configuration_id &&
|
@@ -105,10 +104,11 @@ export const obtainCredential: ObtainCredential = async (
|
|
105
104
|
c.type === credentialDefinition.type
|
106
105
|
);
|
107
106
|
|
108
|
-
if (!
|
109
|
-
throw new ValidationFailed(
|
110
|
-
|
111
|
-
|
107
|
+
if (!containsCredentialDefinition) {
|
108
|
+
throw new ValidationFailed({
|
109
|
+
message:
|
110
|
+
"The access token response does not contain the requested credential",
|
111
|
+
});
|
112
112
|
}
|
113
113
|
|
114
114
|
/** The credential request body */
|
@@ -123,7 +123,7 @@ export const obtainCredential: ObtainCredential = async (
|
|
123
123
|
},
|
124
124
|
};
|
125
125
|
|
126
|
-
const tokenRequestSignedDPop = await
|
126
|
+
const tokenRequestSignedDPop = await createDPopToken(
|
127
127
|
{
|
128
128
|
htm: "POST",
|
129
129
|
htu: credentialUrl,
|
@@ -141,13 +141,16 @@ export const obtainCredential: ObtainCredential = async (
|
|
141
141
|
},
|
142
142
|
body: JSON.stringify(credentialRequestFormBody),
|
143
143
|
})
|
144
|
-
.then(
|
144
|
+
.then(hasStatusOrThrow(200))
|
145
145
|
.then((res) => res.json())
|
146
146
|
.then((body) => CredentialResponse.safeParse(body))
|
147
147
|
.catch(handleObtainCredentialError);
|
148
148
|
|
149
149
|
if (!credentialRes.success) {
|
150
|
-
throw new ValidationFailed(
|
150
|
+
throw new ValidationFailed({
|
151
|
+
message: "Credential Response validation failed",
|
152
|
+
reason: credentialRes.error.message,
|
153
|
+
});
|
151
154
|
}
|
152
155
|
|
153
156
|
return credentialRes.data;
|
@@ -165,28 +168,25 @@ const handleObtainCredentialError = (e: unknown) => {
|
|
165
168
|
throw e;
|
166
169
|
}
|
167
170
|
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
"Invalid status found for the given credential",
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
`Unable to obtain the requested credential [response status code: ${e.statusCode}]`,
|
190
|
-
e.message
|
191
|
-
);
|
171
|
+
throw new ResponseErrorBuilder(IssuerResponseError)
|
172
|
+
.handle(201, {
|
173
|
+
// Although it is technically not an error, we handle it as such to avoid
|
174
|
+
// changing the return type of `obtainCredential` and introduce a breaking change.
|
175
|
+
code: IssuerResponseErrorCodes.CredentialIssuingNotSynchronous,
|
176
|
+
message:
|
177
|
+
"This credential cannot be issued synchronously. It will be available at a later time.",
|
178
|
+
})
|
179
|
+
.handle(403, {
|
180
|
+
code: IssuerResponseErrorCodes.CredentialInvalidStatus,
|
181
|
+
message: "Invalid status found for the given credential",
|
182
|
+
})
|
183
|
+
.handle(404, {
|
184
|
+
code: IssuerResponseErrorCodes.CredentialInvalidStatus,
|
185
|
+
message: "Invalid status found for the given credential",
|
186
|
+
})
|
187
|
+
.handle("*", {
|
188
|
+
code: IssuerResponseErrorCodes.CredentialRequestFailed,
|
189
|
+
message: "Unable to obtain the requested credential",
|
190
|
+
})
|
191
|
+
.buildFrom(e);
|
192
192
|
};
|
@@ -39,20 +39,14 @@ graph TD;
|
|
39
39
|
|
40
40
|
## Mapped results
|
41
41
|
|
42
|
-
|
42
|
+
The following errors are mapped to a `IssuerResponseError` with specific codes.
|
43
43
|
|
44
|
-
|
45
|
-
|
46
|
-
Although `201 Created` is not considered an error, it is mapped as an error in this context in order to handle the case where the credential issuance is not synchronous.
|
47
|
-
This
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
A `403 Forbidden` response is returned by the credential issuer when the requested credential has an invalid status. It might contain more details in the `errorCode` property.
|
52
|
-
|
53
|
-
### 404 Not Found (CredentialInvalidStatusError)
|
54
|
-
|
55
|
-
A `404 Not Found` response is returned by the credential issuer when the authenticated user is not entitled to receive the requested credential. It might contain more details in the `errorCode` property.
|
44
|
+
|HTTP Status|Error Code|Description|
|
45
|
+
|-----------|----------|-----------|
|
46
|
+
|`201 Created`|`ERR_CREDENTIAL_ISSUING_NOT_SYNCHRONOUS`| This response is returned by the credential issuer when the request has been queued because the credential cannot be issued synchronously. The consumer should try to obtain the credential at a later time. Although `201 Created` is not considered an error, it is mapped as an error in this context in order to handle the case where the credential issuance is not synchronous. This allows keeping the flow consistent and handle the case where the credential is not immediately available.|
|
47
|
+
|`403 Forbidden`|`ERR_CREDENTIAL_INVALID_STATUS`|This response is returned by the credential issuer when the requested credential has an invalid status. It might contain more details in the `reason` property.|
|
48
|
+
|`404 Not Found`|`ERR_CREDENTIAL_INVALID_STATUS`| This response is returned by the credential issuer when the authenticated user is not entitled to receive the requested credential. It might contain more details in the `reason` property.|
|
49
|
+
|`*`|`ERR_ISSUER_GENERIC_ERROR`|This is a generic error code to map unexpected errors that occurred when interacting with the Issuer.|
|
56
50
|
|
57
51
|
## Strong authentication for eID issuance (Query Mode)
|
58
52
|
|
@@ -278,7 +272,7 @@ const { issuerRequestUri, clientId, codeVerifier, credentialDefinition } =
|
|
278
272
|
appFetch,
|
279
273
|
});
|
280
274
|
|
281
|
-
// Complete the
|
275
|
+
// Complete the authorization process with query mode with the authorizationContext which opens the browser
|
282
276
|
const { code } =
|
283
277
|
await Credential.Issuance.completeUserAuthorizationWithQueryMode(
|
284
278
|
issuerRequestUri,
|
@@ -0,0 +1,44 @@
|
|
1
|
+
import { IoWalletError, serializeAttrs } from "../../utils/errors";
|
2
|
+
|
3
|
+
/**
|
4
|
+
* An error subclass thrown when an error occurs during the authorization process.
|
5
|
+
*/
|
6
|
+
export class AuthorizationError extends IoWalletError {
|
7
|
+
code = "ERR_IO_WALLET_AUTHORIZATION_ERROR";
|
8
|
+
|
9
|
+
constructor(message?: string) {
|
10
|
+
super(message);
|
11
|
+
}
|
12
|
+
}
|
13
|
+
|
14
|
+
/**
|
15
|
+
* An error subclass thrown when an error occurs during the authorization process with the IDP.
|
16
|
+
* It contains the error and error description returned by the IDP.
|
17
|
+
*/
|
18
|
+
export class AuthorizationIdpError extends IoWalletError {
|
19
|
+
code = "ERR_IO_WALLET_IDENTIFICATION_RESPONSE_PARSING_FAILED";
|
20
|
+
|
21
|
+
error: string;
|
22
|
+
errorDescription?: string;
|
23
|
+
|
24
|
+
constructor(error: string, errorDescription?: string) {
|
25
|
+
super(serializeAttrs({ error, errorDescription }));
|
26
|
+
this.error = error;
|
27
|
+
this.errorDescription = errorDescription;
|
28
|
+
}
|
29
|
+
}
|
30
|
+
|
31
|
+
/**
|
32
|
+
* Error subclass thrown when an operation has been aborted.
|
33
|
+
*/
|
34
|
+
export class OperationAbortedError extends IoWalletError {
|
35
|
+
code = "ERR_IO_WALLET_OPERATION_ABORTED";
|
36
|
+
|
37
|
+
/** The aborted operation */
|
38
|
+
operation: string;
|
39
|
+
|
40
|
+
constructor(operation: string) {
|
41
|
+
super(serializeAttrs({ operation }));
|
42
|
+
this.operation = operation;
|
43
|
+
}
|
44
|
+
}
|
@@ -10,10 +10,12 @@ import {
|
|
10
10
|
import {
|
11
11
|
completeUserAuthorizationWithQueryMode,
|
12
12
|
completeUserAuthorizationWithFormPostJwtMode,
|
13
|
-
|
13
|
+
parseAuthorizationResponse,
|
14
|
+
buildAuthorizationUrl,
|
14
15
|
type CompleteUserAuthorizationWithQueryMode,
|
15
16
|
type CompleteUserAuthorizationWithFormPostJwtMode,
|
16
17
|
type GetRequestedCredentialToBePresented,
|
18
|
+
type BuildAuthorizationUrl,
|
17
19
|
getRequestedCredentialToBePresented,
|
18
20
|
} from "./04-complete-user-authorization";
|
19
21
|
import { authorizeAccess, type AuthorizeAccess } from "./05-authorize-access";
|
@@ -25,22 +27,26 @@ import {
|
|
25
27
|
verifyAndParseCredential,
|
26
28
|
type VerifyAndParseCredential,
|
27
29
|
} from "./07-verify-and-parse-credential";
|
30
|
+
import * as Errors from "./errors";
|
28
31
|
|
29
32
|
export {
|
30
33
|
evaluateIssuerTrust,
|
31
34
|
startUserAuthorization,
|
35
|
+
buildAuthorizationUrl,
|
32
36
|
completeUserAuthorizationWithQueryMode,
|
33
37
|
getRequestedCredentialToBePresented,
|
34
38
|
completeUserAuthorizationWithFormPostJwtMode,
|
35
39
|
authorizeAccess,
|
36
40
|
obtainCredential,
|
37
41
|
verifyAndParseCredential,
|
38
|
-
|
42
|
+
parseAuthorizationResponse,
|
43
|
+
Errors,
|
39
44
|
};
|
40
45
|
export type {
|
41
46
|
StartFlow,
|
42
47
|
EvaluateIssuerTrust,
|
43
48
|
StartUserAuthorization,
|
49
|
+
BuildAuthorizationUrl,
|
44
50
|
CompleteUserAuthorizationWithQueryMode,
|
45
51
|
GetRequestedCredentialToBePresented,
|
46
52
|
CompleteUserAuthorizationWithFormPostJwtMode,
|
@@ -30,11 +30,3 @@ export const ResponseUriResultShape = z.object({
|
|
30
30
|
});
|
31
31
|
|
32
32
|
export type ResponseMode = "query" | "form_post.jwt";
|
33
|
-
|
34
|
-
export const CredentialIssuanceFailureResponse = z.object({
|
35
|
-
error: z.string(),
|
36
|
-
});
|
37
|
-
|
38
|
-
export type CredentialIssuanceFailureResponse = z.infer<
|
39
|
-
typeof CredentialIssuanceFailureResponse
|
40
|
-
>;
|