@pagopa/io-react-native-wallet 0.11.0 → 0.12.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
};
|