@pagopa/io-react-native-wallet 0.11.0 → 0.12.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.
- package/lib/commonjs/client/generated/wallet-provider.js +126 -0
- package/lib/commonjs/client/generated/wallet-provider.js.map +1 -0
- package/lib/commonjs/client/index.js +41 -0
- package/lib/commonjs/client/index.js.map +1 -0
- package/lib/commonjs/credential/issuance/07-verify-and-parse-credential.js +6 -6
- package/lib/commonjs/credential/issuance/07-verify-and-parse-credential.js.map +1 -1
- package/lib/commonjs/index.js +10 -1
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/utils/errors.js +29 -1
- package/lib/commonjs/utils/errors.js.map +1 -1
- package/lib/commonjs/utils/integrity.js +2 -0
- package/lib/commonjs/utils/integrity.js.map +1 -0
- package/lib/commonjs/wallet-instance/index.js +29 -0
- package/lib/commonjs/wallet-instance/index.js.map +1 -0
- package/lib/commonjs/wallet-instance-attestation/issuing.js +48 -66
- package/lib/commonjs/wallet-instance-attestation/issuing.js.map +1 -1
- package/lib/commonjs/wallet-instance-attestation/types.js +1 -1
- package/lib/commonjs/wallet-instance-attestation/types.js.map +1 -1
- package/lib/module/client/generated/wallet-provider.js +105 -0
- package/lib/module/client/generated/wallet-provider.js.map +1 -0
- package/lib/module/client/index.js +34 -0
- package/lib/module/client/index.js.map +1 -0
- package/lib/module/credential/issuance/07-verify-and-parse-credential.js +6 -6
- package/lib/module/credential/issuance/07-verify-and-parse-credential.js.map +1 -1
- package/lib/module/index.js +3 -1
- package/lib/module/index.js.map +1 -1
- package/lib/module/sd-jwt/verifier.js.map +1 -1
- package/lib/module/utils/errors.js +27 -0
- package/lib/module/utils/errors.js.map +1 -1
- package/lib/module/utils/integrity.js +2 -0
- package/lib/module/utils/integrity.js.map +1 -0
- package/lib/module/wallet-instance/index.js +23 -0
- package/lib/module/wallet-instance/index.js.map +1 -0
- package/lib/module/wallet-instance-attestation/issuing.js +48 -67
- package/lib/module/wallet-instance-attestation/issuing.js.map +1 -1
- package/lib/module/wallet-instance-attestation/types.js +1 -1
- package/lib/module/wallet-instance-attestation/types.js.map +1 -1
- package/lib/typescript/client/generated/wallet-provider.d.ts +242 -0
- package/lib/typescript/client/generated/wallet-provider.d.ts.map +1 -0
- package/lib/typescript/client/index.d.ts +7 -0
- package/lib/typescript/client/index.d.ts.map +1 -0
- package/lib/typescript/credential/issuance/07-verify-and-parse-credential.d.ts.map +1 -1
- package/lib/typescript/index.d.ts +5 -1
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/utils/errors.d.ts +13 -0
- package/lib/typescript/utils/errors.d.ts.map +1 -1
- package/lib/typescript/utils/integrity.d.ts +21 -0
- package/lib/typescript/utils/integrity.d.ts.map +1 -0
- package/lib/typescript/wallet-instance/index.d.ts +7 -0
- package/lib/typescript/wallet-instance/index.d.ts.map +1 -0
- package/lib/typescript/wallet-instance-attestation/issuing.d.ts +15 -3
- package/lib/typescript/wallet-instance-attestation/issuing.d.ts.map +1 -1
- package/lib/typescript/wallet-instance-attestation/types.d.ts +5 -5
- package/package.json +9 -6
- package/src/client/generated/wallet-provider.ts +170 -0
- package/src/client/index.ts +58 -0
- package/src/credential/issuance/07-verify-and-parse-credential.ts +38 -34
- package/src/index.ts +7 -0
- package/src/sd-jwt/__test__/converters.test.js +24 -0
- package/src/sd-jwt/verifier.js +12 -0
- package/src/utils/errors.ts +28 -0
- package/src/utils/integrity.ts +23 -0
- package/src/wallet-instance/index.ts +29 -0
- package/src/wallet-instance-attestation/issuing.ts +68 -101
- package/src/wallet-instance-attestation/types.ts +1 -1
@@ -0,0 +1,58 @@
|
|
1
|
+
import { WalletProviderResponseError } from "../utils/errors";
|
2
|
+
import {
|
3
|
+
ProblemDetail,
|
4
|
+
createApiClient as createWalletProviderApiClient,
|
5
|
+
} from "./generated/wallet-provider";
|
6
|
+
import { ApiClient as WalletProviderApiClient } from "./generated/wallet-provider";
|
7
|
+
|
8
|
+
export type WalletProviderClient = WalletProviderApiClient;
|
9
|
+
|
10
|
+
const validateResponse = async (response: Response) => {
|
11
|
+
if (!response.ok) {
|
12
|
+
let problemDetail: ProblemDetail = {};
|
13
|
+
try {
|
14
|
+
problemDetail = ProblemDetail.parse(await response.json());
|
15
|
+
} catch {
|
16
|
+
problemDetail = {
|
17
|
+
title: "Invalid response from Wallet Provider",
|
18
|
+
};
|
19
|
+
}
|
20
|
+
|
21
|
+
let statusResponse = `Response status code: ${response.status}`;
|
22
|
+
|
23
|
+
throw new WalletProviderResponseError(
|
24
|
+
problemDetail.title
|
25
|
+
? problemDetail.title
|
26
|
+
: "Invalid response from Wallet Provider",
|
27
|
+
problemDetail.type,
|
28
|
+
problemDetail.detail
|
29
|
+
? statusResponse
|
30
|
+
: `${statusResponse} with detail: ${problemDetail.detail}`
|
31
|
+
);
|
32
|
+
}
|
33
|
+
return response;
|
34
|
+
};
|
35
|
+
|
36
|
+
export const getWalletProviderClient = (context: {
|
37
|
+
walletProviderBaseUrl: string;
|
38
|
+
appFetch?: GlobalFetch["fetch"];
|
39
|
+
}) => {
|
40
|
+
const { walletProviderBaseUrl, appFetch = fetch } = context;
|
41
|
+
|
42
|
+
return createWalletProviderApiClient(
|
43
|
+
(method, url, params) =>
|
44
|
+
appFetch(url, {
|
45
|
+
method,
|
46
|
+
body: params ? JSON.stringify(params.body) : undefined,
|
47
|
+
})
|
48
|
+
.then(validateResponse)
|
49
|
+
.then((res) => {
|
50
|
+
const contentType = res.headers.get("content-type");
|
51
|
+
if (contentType === "application/json") {
|
52
|
+
return res.json();
|
53
|
+
}
|
54
|
+
return res.text();
|
55
|
+
}),
|
56
|
+
walletProviderBaseUrl
|
57
|
+
);
|
58
|
+
};
|
@@ -89,45 +89,49 @@ const parseCredentialSdJwt = (
|
|
89
89
|
|
90
90
|
// attributes that are defined in the issuer configuration
|
91
91
|
// and are present in the disclosure set
|
92
|
-
const definedValues =
|
93
|
-
|
94
|
-
|
95
|
-
(
|
96
|
-
[
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
(
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
(
|
110
|
-
[
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
92
|
+
const definedValues = Object.fromEntries(
|
93
|
+
attrDefinitions
|
94
|
+
// retrieve the value from the disclosure set
|
95
|
+
.map(
|
96
|
+
([attrKey, definition]) =>
|
97
|
+
[
|
98
|
+
attrKey,
|
99
|
+
{
|
100
|
+
...definition,
|
101
|
+
value: disclosures.find(
|
102
|
+
(_) => _[1 /* name */] === attrKey
|
103
|
+
)?.[2 /* value */],
|
104
|
+
},
|
105
|
+
] as const
|
106
|
+
)
|
107
|
+
// add a human readable attribute name, with i18n, in the form { locale: name }
|
108
|
+
// example: { "it-IT": "Nome", "en-EN": "Name", "es-ES": "Nombre" }
|
109
|
+
.map(
|
110
|
+
([attrKey, { display, ...definition }]) =>
|
111
|
+
[
|
112
|
+
attrKey,
|
113
|
+
{
|
114
|
+
...definition,
|
115
|
+
name: display.reduce(
|
116
|
+
(names, { locale, name }) => ({ ...names, [locale]: name }),
|
117
|
+
{} as Record<string, string>
|
118
|
+
),
|
119
|
+
},
|
120
|
+
] as const
|
121
|
+
)
|
122
|
+
);
|
121
123
|
|
122
124
|
// attributes that are in the disclosure set
|
123
125
|
// but are not defined in the issuer configuration
|
124
|
-
const undefinedValues =
|
125
|
-
|
126
|
-
|
126
|
+
const undefinedValues = Object.fromEntries(
|
127
|
+
disclosures
|
128
|
+
.filter((_) => !Object.keys(definedValues).includes(_[1]))
|
129
|
+
.map(([, key, value]) => [key, { value, mandatory: false, name: key }])
|
130
|
+
);
|
127
131
|
|
128
132
|
return {
|
129
|
-
...
|
130
|
-
...
|
133
|
+
...definedValues,
|
134
|
+
...undefinedValues,
|
131
135
|
};
|
132
136
|
};
|
133
137
|
|
package/src/index.ts
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
import { fixBase64EncodingOnKey } from "./utils/jwk";
|
1
2
|
// polyfill due to known bugs on URL implementation for react native
|
2
3
|
// https://github.com/facebook/react-native/issues/24428
|
3
4
|
import "react-native-url-polyfill/auto";
|
@@ -8,17 +9,23 @@ import * as SdJwt from "./sd-jwt";
|
|
8
9
|
import * as Errors from "./utils/errors";
|
9
10
|
import * as WalletInstanceAttestation from "./wallet-instance-attestation";
|
10
11
|
import * as Trust from "./trust";
|
12
|
+
import * as WalletInstance from "./wallet-instance";
|
11
13
|
import { AuthorizationDetail, AuthorizationDetails } from "./utils/par";
|
12
14
|
import { createCryptoContextFor } from "./utils/crypto";
|
15
|
+
import type { IntegrityContext } from "./utils/integrity";
|
13
16
|
|
14
17
|
export {
|
15
18
|
SdJwt,
|
16
19
|
PID,
|
17
20
|
Credential,
|
18
21
|
WalletInstanceAttestation,
|
22
|
+
WalletInstance,
|
19
23
|
Errors,
|
20
24
|
Trust,
|
21
25
|
createCryptoContextFor,
|
22
26
|
AuthorizationDetail,
|
23
27
|
AuthorizationDetails,
|
28
|
+
fixBase64EncodingOnKey,
|
24
29
|
};
|
30
|
+
|
31
|
+
export type { IntegrityContext };
|
@@ -0,0 +1,24 @@
|
|
1
|
+
import { getValueFromDisclosures } from "../converters";
|
2
|
+
const disclosures = [
|
3
|
+
["6w1_soRXFgaHKfpYn3cvfQ", "given_name", "Mario"],
|
4
|
+
["fuNp97Hf3wV6y48y-QZhIg", "birthdate", "1980-10-01"],
|
5
|
+
[
|
6
|
+
"p-9LzyWHZBVDvhXDWkN2xA",
|
7
|
+
"place_of_birth",
|
8
|
+
{ country: "IT", locality: "Rome" },
|
9
|
+
],
|
10
|
+
];
|
11
|
+
describe("getValueFromDisclosures", () => {
|
12
|
+
it("should return correct value for given_name", () => {
|
13
|
+
const success = getValueFromDisclosures(disclosures, "given_name");
|
14
|
+
expect(success).toBe("Mario");
|
15
|
+
});
|
16
|
+
it("should return correct value for place_of_birth", () => {
|
17
|
+
const success = getValueFromDisclosures(disclosures, "place_of_birth");
|
18
|
+
expect(success).toEqual({ country: "IT", locality: "Rome" });
|
19
|
+
});
|
20
|
+
it("should fail", () => {
|
21
|
+
const success = getValueFromDisclosures(disclosures, "given_surname");
|
22
|
+
expect(success).toBeUndefined();
|
23
|
+
});
|
24
|
+
});
|
@@ -0,0 +1,12 @@
|
|
1
|
+
import { sha256ToBase64 } from "@pagopa/io-react-native-jwt";
|
2
|
+
import { ValidationFailed } from "../utils/errors";
|
3
|
+
export const verifyDisclosure = async ({ encoded, decoded }, claims) => {
|
4
|
+
let hash = await sha256ToBase64(encoded);
|
5
|
+
if (!claims.includes(hash)) {
|
6
|
+
throw new ValidationFailed(
|
7
|
+
"Validation of disclosure failed",
|
8
|
+
`${decoded}`,
|
9
|
+
"Disclosure hash not found in claims"
|
10
|
+
);
|
11
|
+
}
|
12
|
+
};
|
package/src/utils/errors.ts
CHANGED
@@ -233,3 +233,31 @@ export class PidMetadataError extends Error {
|
|
233
233
|
super(message);
|
234
234
|
}
|
235
235
|
}
|
236
|
+
|
237
|
+
/**
|
238
|
+
* An error subclass thrown when a Wallet Provider http request fail
|
239
|
+
*
|
240
|
+
*/
|
241
|
+
export class WalletProviderResponseError extends IoWalletError {
|
242
|
+
static get code(): "ERR_IO_WALLET_PROVIDER_RESPONSE_FAILED" {
|
243
|
+
return "ERR_IO_WALLET_PROVIDER_RESPONSE_FAILED";
|
244
|
+
}
|
245
|
+
|
246
|
+
code = "ERR_IO_WALLET_PROVIDER_RESPONSE_FAILED";
|
247
|
+
|
248
|
+
/** The Claim for which the validation failed. */
|
249
|
+
claim: string;
|
250
|
+
|
251
|
+
/** Reason code for the validation failure. */
|
252
|
+
reason: string;
|
253
|
+
|
254
|
+
constructor(
|
255
|
+
message: string,
|
256
|
+
claim: string = "unspecified",
|
257
|
+
reason: string = "unspecified"
|
258
|
+
) {
|
259
|
+
super(serializeAttrs({ message, claim, reason }));
|
260
|
+
this.claim = claim;
|
261
|
+
this.reason = reason;
|
262
|
+
}
|
263
|
+
}
|
@@ -0,0 +1,23 @@
|
|
1
|
+
/**
|
2
|
+
* Interface for the integrity context which provides the necessary functions to interact with the integrity service.
|
3
|
+
* The functions are platform specific and must be implemented in the platform specific code.
|
4
|
+
* getHardwareKeyTag: returns the hardware key tag.
|
5
|
+
* getAttestation: requests the attestation from the integrity service.
|
6
|
+
* getHardwareSignatureWithAuthData: signs the clientData and returns the signature with the authenticator data.
|
7
|
+
*/
|
8
|
+
export interface IntegrityContext {
|
9
|
+
getHardwareKeyTag: () => string;
|
10
|
+
getAttestation: (nonce: string) => Promise<string>;
|
11
|
+
getHardwareSignatureWithAuthData: (
|
12
|
+
clientData: string
|
13
|
+
) => Promise<HardwareSignatureWithAuthData>;
|
14
|
+
}
|
15
|
+
|
16
|
+
/**
|
17
|
+
* Type returned by the getHardwareSignatureWithAuthData function of {@link IntegrityContext}.
|
18
|
+
* It contains the signature and the authenticator data.
|
19
|
+
*/
|
20
|
+
export type HardwareSignatureWithAuthData = {
|
21
|
+
signature: string;
|
22
|
+
authenticatorData: string;
|
23
|
+
};
|
@@ -0,0 +1,29 @@
|
|
1
|
+
import { getWalletProviderClient } from "../client";
|
2
|
+
import type { IntegrityContext } from "..";
|
3
|
+
|
4
|
+
export async function createWalletInstance(context: {
|
5
|
+
integrityContext: IntegrityContext;
|
6
|
+
walletProviderBaseUrl: string;
|
7
|
+
appFetch?: GlobalFetch["fetch"];
|
8
|
+
}) {
|
9
|
+
const { integrityContext } = context;
|
10
|
+
|
11
|
+
const api = getWalletProviderClient(context);
|
12
|
+
|
13
|
+
//1. Obtain nonce
|
14
|
+
const challenge = await api.get("/nonce").then((response) => response.nonce);
|
15
|
+
|
16
|
+
const keyAttestation = await integrityContext.getAttestation(challenge);
|
17
|
+
const hardwareKeyTag = integrityContext.getHardwareKeyTag();
|
18
|
+
|
19
|
+
//2. Create Wallet Instance
|
20
|
+
await api.post("/wallet-instances", {
|
21
|
+
body: {
|
22
|
+
challenge,
|
23
|
+
key_attestation: keyAttestation,
|
24
|
+
hardware_key_tag: hardwareKeyTag,
|
25
|
+
},
|
26
|
+
});
|
27
|
+
|
28
|
+
return hardwareKeyTag;
|
29
|
+
}
|
@@ -1,77 +1,62 @@
|
|
1
|
-
import {
|
2
|
-
type CryptoContext,
|
3
|
-
decode as decodeJwt,
|
4
|
-
} from "@pagopa/io-react-native-jwt";
|
5
|
-
import { verify as verifyJwt } from "@pagopa/io-react-native-jwt";
|
1
|
+
import { type CryptoContext } from "@pagopa/io-react-native-jwt";
|
6
2
|
import { SignJWT, thumbprint } from "@pagopa/io-react-native-jwt";
|
7
3
|
import { JWK, fixBase64EncodingOnKey } from "../utils/jwk";
|
8
|
-
import {
|
9
|
-
import
|
10
|
-
import {
|
11
|
-
import type { WalletProviderEntityConfiguration } from "../trust/types";
|
4
|
+
import { getWalletProviderClient } from "../client";
|
5
|
+
import type { IntegrityContext } from "..";
|
6
|
+
import { z } from "zod";
|
12
7
|
|
13
|
-
|
8
|
+
/**
|
9
|
+
* Getter for an attestation request. The attestation request is a JWT that will be sent to the Wallet Provider to request a Wallet Instance Attestation.
|
10
|
+
*
|
11
|
+
* @param challenge - The nonce received from the Wallet Provider which is part of the signed clientData
|
12
|
+
* @param wiaCryptoContext - The key pair associated with the WIA. Will be use to prove the ownership of the attestation
|
13
|
+
* @param integrityContext - The integrity context which exposes a set of functions to interact with the device integrity service
|
14
|
+
* @param walletProviderBaseUrl - Base url for the Wallet Provider
|
15
|
+
* @returns A JWT containing the attestation request
|
16
|
+
*/
|
17
|
+
export async function getAttestationRequest(
|
18
|
+
challenge: string,
|
14
19
|
wiaCryptoContext: CryptoContext,
|
15
|
-
|
20
|
+
integrityContext: IntegrityContext,
|
21
|
+
walletProviderBaseUrl: string
|
16
22
|
): Promise<string> {
|
17
23
|
const jwk = await wiaCryptoContext.getPublicKey();
|
18
24
|
const parsedJwk = JWK.parse(jwk);
|
19
25
|
const keyThumbprint = await thumbprint(parsedJwk);
|
20
26
|
const publicKey = { ...parsedJwk, kid: keyThumbprint };
|
21
27
|
|
28
|
+
const clientData = {
|
29
|
+
challenge,
|
30
|
+
jwk_thumbprint: keyThumbprint,
|
31
|
+
};
|
32
|
+
|
33
|
+
const hardwareKeyTag = integrityContext.getHardwareKeyTag();
|
34
|
+
const { signature, authenticatorData } =
|
35
|
+
await integrityContext.getHardwareSignatureWithAuthData(
|
36
|
+
JSON.stringify(clientData)
|
37
|
+
);
|
38
|
+
|
22
39
|
return new SignJWT(wiaCryptoContext)
|
23
40
|
.setPayload({
|
24
41
|
iss: keyThumbprint,
|
25
|
-
|
26
|
-
|
27
|
-
|
42
|
+
sub: walletProviderBaseUrl,
|
43
|
+
challenge,
|
44
|
+
hardware_signature: signature,
|
45
|
+
integrity_assertion: authenticatorData,
|
46
|
+
hardware_key_tag: hardwareKeyTag,
|
28
47
|
cnf: {
|
29
48
|
jwk: fixBase64EncodingOnKey(publicKey),
|
30
49
|
},
|
31
50
|
})
|
32
51
|
.setProtectedHeader({
|
33
52
|
kid: publicKey.kid,
|
34
|
-
typ: "
|
53
|
+
typ: "war+jwt",
|
35
54
|
})
|
36
55
|
.setIssuedAt()
|
37
56
|
.setExpirationTime("1h")
|
38
57
|
.sign();
|
39
58
|
}
|
40
59
|
|
41
|
-
/**
|
42
|
-
* Validate a Wallet Instance Attestation token.
|
43
|
-
* Either return true or throw an exception.
|
44
|
-
*
|
45
|
-
* @param wia Signed Wallet Instance Attestation token
|
46
|
-
* @param walletProviderEntityConfiguration Entity Configuration object for the issuing Wallet Provider
|
47
|
-
* @returns The token is valid
|
48
|
-
* @throws {WalletInstanceAttestationIssuingError} When the received token fails to validate. This can happen due to invalid signature, expired token or malformed JWT token.
|
49
|
-
*/
|
50
|
-
async function verifyWalletInstanceAttestation(
|
51
|
-
wia: string,
|
52
|
-
walletProviderEntityConfiguration: WalletProviderEntityConfiguration
|
53
|
-
): Promise<true> {
|
54
|
-
const {
|
55
|
-
payload: {
|
56
|
-
sub,
|
57
|
-
metadata: {
|
58
|
-
wallet_provider: {
|
59
|
-
jwks: { keys },
|
60
|
-
},
|
61
|
-
},
|
62
|
-
},
|
63
|
-
} = walletProviderEntityConfiguration;
|
64
|
-
return verifyJwt(wia, keys, { issuer: sub })
|
65
|
-
.then((_) => true as const)
|
66
|
-
.catch((ex) => {
|
67
|
-
const reason = ex && ex instanceof Error ? ex.message : "unknown reason";
|
68
|
-
throw new WalletInstanceAttestationIssuingError(
|
69
|
-
"Unable to validate received wallet instance attestation",
|
70
|
-
reason
|
71
|
-
);
|
72
|
-
});
|
73
|
-
}
|
74
|
-
|
75
60
|
/**
|
76
61
|
* Request a Wallet Instance Attestation (WIA) to the Wallet provider
|
77
62
|
*
|
@@ -80,60 +65,42 @@ async function verifyWalletInstanceAttestation(
|
|
80
65
|
* @param walletProviderBaseUrl Base url for the Wallet Provider
|
81
66
|
* @returns The retrieved Wallet Instance Attestation token
|
82
67
|
*/
|
83
|
-
export const getAttestation =
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
68
|
+
export const getAttestation = async ({
|
69
|
+
wiaCryptoContext,
|
70
|
+
integrityContext,
|
71
|
+
walletProviderBaseUrl,
|
72
|
+
appFetch = fetch,
|
73
|
+
}: {
|
74
|
+
wiaCryptoContext: CryptoContext;
|
75
|
+
integrityContext: IntegrityContext;
|
76
|
+
walletProviderBaseUrl: string;
|
77
|
+
appFetch?: GlobalFetch["fetch"];
|
78
|
+
}): Promise<string> => {
|
79
|
+
const api = getWalletProviderClient({
|
80
|
+
walletProviderBaseUrl,
|
81
|
+
appFetch,
|
82
|
+
});
|
98
83
|
|
99
|
-
|
100
|
-
|
101
|
-
payload: decodedRequest.payload,
|
102
|
-
header: decodedRequest.protectedHeader,
|
103
|
-
});
|
104
|
-
const publicKey = parsedRequest.payload.cnf.jwk;
|
84
|
+
// 1. Get nonce from backend
|
85
|
+
const challenge = await api.get("/nonce").then((response) => response.nonce);
|
105
86
|
|
106
|
-
|
87
|
+
// 2. Get a signed attestation request
|
88
|
+
const signedAttestationRequest = await getAttestationRequest(
|
89
|
+
challenge,
|
90
|
+
wiaCryptoContext,
|
91
|
+
integrityContext,
|
92
|
+
walletProviderBaseUrl
|
93
|
+
);
|
107
94
|
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
assertion: signedAttestationRequest,
|
115
|
-
};
|
116
|
-
const response = await appFetch(tokenUrl, {
|
117
|
-
method: "POST",
|
118
|
-
headers: {
|
119
|
-
"Content-Type": "application/json",
|
95
|
+
// 3. Request WIA
|
96
|
+
const wia = await api
|
97
|
+
.post("/token", {
|
98
|
+
body: {
|
99
|
+
grant_type: "urn:ietf:params:oauth:grant-type:jwt-bearer",
|
100
|
+
assertion: signedAttestationRequest,
|
120
101
|
},
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
if (response.status !== 201) {
|
125
|
-
throw new WalletInstanceAttestationIssuingError(
|
126
|
-
"Unable to obtain wallet instance attestation from wallet provider",
|
127
|
-
`Response code: ${response.status}`
|
128
|
-
);
|
129
|
-
}
|
130
|
-
|
131
|
-
const wia = await response.text();
|
132
|
-
|
133
|
-
await verifyWalletInstanceAttestation(
|
134
|
-
wia,
|
135
|
-
walletProviderEntityConfiguration
|
136
|
-
);
|
102
|
+
})
|
103
|
+
.then((result) => z.string().parse(result));
|
137
104
|
|
138
|
-
|
139
|
-
|
105
|
+
return wia;
|
106
|
+
};
|