@pagopa/io-react-native-wallet 0.16.3 → 0.17.1
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/README.md +146 -197
- package/lib/commonjs/cie/README.md +6 -0
- package/lib/commonjs/cie/component.js +3 -1
- package/lib/commonjs/cie/component.js.map +1 -1
- package/lib/commonjs/credential/issuance/06-obtain-credential.js +6 -0
- package/lib/commonjs/credential/issuance/06-obtain-credential.js.map +1 -1
- package/lib/commonjs/credential/issuance/README.md +323 -0
- package/lib/commonjs/credential/presentation/README.md +3 -0
- package/lib/commonjs/credential/status/README.md +64 -0
- package/lib/commonjs/utils/errors.js +20 -1
- package/lib/commonjs/utils/errors.js.map +1 -1
- package/lib/commonjs/wallet-instance/README.md +29 -0
- package/lib/commonjs/wallet-instance-attestation/README.md +35 -0
- package/lib/module/cie/README.md +6 -0
- package/lib/module/cie/component.js +2 -1
- package/lib/module/cie/component.js.map +1 -1
- package/lib/module/credential/issuance/06-obtain-credential.js +7 -1
- package/lib/module/credential/issuance/06-obtain-credential.js.map +1 -1
- package/lib/module/credential/issuance/README.md +323 -0
- package/lib/module/credential/presentation/README.md +3 -0
- package/lib/module/credential/status/README.md +64 -0
- package/lib/module/utils/errors.js +18 -0
- package/lib/module/utils/errors.js.map +1 -1
- package/lib/module/wallet-instance/README.md +29 -0
- package/lib/module/wallet-instance-attestation/README.md +35 -0
- package/lib/typescript/cie/component.d.ts.map +1 -1
- package/lib/typescript/credential/issuance/06-obtain-credential.d.ts.map +1 -1
- package/lib/typescript/utils/errors.d.ts +9 -0
- package/lib/typescript/utils/errors.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/cie/README.md +6 -0
- package/src/cie/component.tsx +3 -1
- package/src/credential/issuance/06-obtain-credential.ts +10 -0
- package/src/credential/issuance/README.md +323 -0
- package/src/credential/presentation/README.md +3 -0
- package/src/credential/status/README.md +64 -0
- package/src/utils/errors.ts +18 -0
- package/src/wallet-instance/README.md +29 -0
- package/src/wallet-instance-attestation/README.md +35 -0
@@ -0,0 +1,323 @@
|
|
1
|
+
# Credential Issuance
|
2
|
+
|
3
|
+
This flow is used to obtain a credential from a credential issuer. Each step in the flow is imported from the related file which is named with a sequential number.
|
4
|
+
|
5
|
+
There's a fork in the flow which is based on the type of the credential that is being requested. If the credential is an eID, the flow takes a different path than if it is not an eID.
|
6
|
+
This is due to the fact that eID credentials require a different authorization flow than other credentials, which is accomplished by a strong authentication method like SPID or CIE.
|
7
|
+
Credentials instead require a simpler authorization flow and they require other credentials to be presented in order to be issued.
|
8
|
+
|
9
|
+
The supported credentials are defined in the entity configuration of the issuer which is evaluted and parsed in the `evaluateIssuerTrust` step.
|
10
|
+
|
11
|
+
## Sequence Diagram
|
12
|
+
|
13
|
+
```mermaid
|
14
|
+
graph TD;
|
15
|
+
0[WalletInstanceAttestation.getAttestation]
|
16
|
+
1[startFlow]
|
17
|
+
2[evaluateIssuerTrust]
|
18
|
+
3[startUserAuthorization]
|
19
|
+
C4[getRequestedCredentialToBePresented]
|
20
|
+
C4.1[completeUserAuthorizationWithFormPostJwtMode]
|
21
|
+
E4[completeUserAuthorizationWithQueryMode]
|
22
|
+
5[authorizeAccess]
|
23
|
+
6[obtainCredential]
|
24
|
+
7[verifyAndParseCredential]
|
25
|
+
credSel{Is credential an eID?}
|
26
|
+
|
27
|
+
0 --> 1
|
28
|
+
1 --> 2
|
29
|
+
2 --> 3
|
30
|
+
3 --> credSel
|
31
|
+
credSel -->|Yes| E4
|
32
|
+
credSel -->|No| C4
|
33
|
+
C4 --> C4.1
|
34
|
+
C4.1 --> 5
|
35
|
+
E4 --> 5
|
36
|
+
5 --> 6
|
37
|
+
6 --> 7
|
38
|
+
```
|
39
|
+
|
40
|
+
## Mapped results
|
41
|
+
|
42
|
+
### 404 Not Found (CredentialNotEntitledError)
|
43
|
+
|
44
|
+
A `404 Not Found` response is returned by the credential issuer when the authenticated user is not entitled to receive the requested credential.
|
45
|
+
|
46
|
+
## Strong authentication for eID issuance (Query Mode)
|
47
|
+
|
48
|
+
The eID issuance requires a strong authentication method. Currently SPID (L2), CieID (L2) and CIE+PIN (L3) are supported. The strong authentication method is determined by the IDP hint which is passed to the `completeUserAuthorizationWithQueryMode` function.
|
49
|
+
|
50
|
+
For SPID in production the IDP hint can be found [here](https://registry.spid.gov.it/identity-providers), under the `entityId` field. For pre-production environment the IDP hint is `https://demo.spid.gov.it'`.
|
51
|
+
|
52
|
+
For CieID(L2) the IDP hint is `https://idserver.servizicie.interno.gov.it/idp/profile/SAML2/POST/SSO"` for production and `https://collaudo.idserver.servizicie.interno.gov.it/idp/profile/SAML2/POST/SSO` for pre-production.
|
53
|
+
|
54
|
+
CIE+PIN(L3) requires a different flow due to the physical card presence. Helper functions are exposed to handle it and the documentation can be found [here](../../cie/README.md).
|
55
|
+
|
56
|
+
The expected result from the authentication process is in provided in the query string as defined in the [JWT Secured Authorization Response Mode for OAuth 2.0 (JARM)](https://openid.net/specs/oauth-v2-jarm.html#name-response-mode-queryjwt).
|
57
|
+
|
58
|
+
## Authentication through credentials (Form Post JWT Mode)
|
59
|
+
|
60
|
+
When the credential is different than an eID, the flow requires the user to present other credentials in order to obtain the requested one. This is done through the `getRequestedCredentialToBePresented` followed by the `completeUserAuthorizationWithFormPostJwtMode`.
|
61
|
+
|
62
|
+
The expected result from the authentication process is in `form_post.jwt` format as defined in [JWT Secured Authorization Response Mode for OAuth 2.0 (JARM)](https://openid.net/specs/oauth-v2-jarm.html#name-response-mode-form_postjwt).
|
63
|
+
|
64
|
+
## Examples
|
65
|
+
|
66
|
+
<details>
|
67
|
+
<summary>Credential issuance flow</summary>
|
68
|
+
|
69
|
+
```ts
|
70
|
+
// Retrieve the integrity key tag from the store and create its context
|
71
|
+
const integrityKeyTag = "example"; // Let's assume this is the key tag used to create the wallet instance
|
72
|
+
const integrityContext = getIntegrityContext(integrityKeyTag);
|
73
|
+
|
74
|
+
// generate Key for Wallet Instance Attestation
|
75
|
+
// ensure the key esists befor starting the issuing process
|
76
|
+
await regenerateCryptoKey(WIA_KEYTAG); // Let's assume this function regenerates this ephemeral key
|
77
|
+
const wiaCryptoContext = createCryptoContextFor(WIA_KEYTAG);
|
78
|
+
|
79
|
+
const { WALLET_PROVIDER_BASE_URL, WALLET_EAA_PROVIDER_BASE_URL, REDIRECT_URI } =
|
80
|
+
env; // Let's assume these are the environment variables
|
81
|
+
|
82
|
+
/**
|
83
|
+
* Obtains a new Wallet Instance Attestation.
|
84
|
+
* WARNING: The integrity context must be the same used when creating the Wallet Instance with the same keytag.
|
85
|
+
*/
|
86
|
+
const walletInstanceAttestation =
|
87
|
+
await WalletInstanceAttestation.getAttestation({
|
88
|
+
wiaCryptoContext,
|
89
|
+
integrityContext,
|
90
|
+
walletProviderBaseUrl: WALLET_PROVIDER_BASE_URL,
|
91
|
+
appFetch,
|
92
|
+
});
|
93
|
+
|
94
|
+
const credentialType = "someCredential"; // Let's assume this is the credential type
|
95
|
+
|
96
|
+
const eid = {
|
97
|
+
credential: "example",
|
98
|
+
parsedCredential: "example"
|
99
|
+
keyTag: "example";
|
100
|
+
credentialType: "eid";
|
101
|
+
};
|
102
|
+
|
103
|
+
const eidCryptoContext = createCryptoContextFor(eid.keyTag);
|
104
|
+
|
105
|
+
// Create credential crypto context
|
106
|
+
const credentialKeyTag = uuid.v4().toString();
|
107
|
+
await generate(credentialKeyTag); // Let's assume this function generates a new hardware-backed key pair
|
108
|
+
const credentialCryptoContext = createCryptoContextFor(credentialKeyTag);
|
109
|
+
|
110
|
+
// Start the issuance flow
|
111
|
+
const startFlow: Credential.Issuance.StartFlow = () => ({
|
112
|
+
issuerUrl: WALLET_EAA_PROVIDER_BASE_URL,
|
113
|
+
credentialType,
|
114
|
+
});
|
115
|
+
|
116
|
+
const { issuerUrl } = startFlow();
|
117
|
+
|
118
|
+
// Evaluate issuer trust
|
119
|
+
const { issuerConf } = await Credential.Issuance.evaluateIssuerTrust(issuerUrl);
|
120
|
+
|
121
|
+
// Start user authorization
|
122
|
+
const { issuerRequestUri, clientId, codeVerifier, credentialDefinition } =
|
123
|
+
await Credential.Issuance.startUserAuthorization(issuerConf, credentialType, {
|
124
|
+
walletInstanceAttestation,
|
125
|
+
redirectUri,
|
126
|
+
wiaCryptoContext,
|
127
|
+
appFetch,
|
128
|
+
});
|
129
|
+
|
130
|
+
const requestObject =
|
131
|
+
await Credential.Issuance.getRequestedCredentialToBePresented(
|
132
|
+
issuerRequestUri,
|
133
|
+
clientId,
|
134
|
+
issuerConf,
|
135
|
+
appFetch
|
136
|
+
);
|
137
|
+
|
138
|
+
// The app here should ask the user to confirm the required data contained in the requestObject
|
139
|
+
|
140
|
+
// Complete the user authorization via form_post.jwt mode
|
141
|
+
const { code } =
|
142
|
+
await Credential.Issuance.completeUserAuthorizationWithFormPostJwtMode(
|
143
|
+
requestObject,
|
144
|
+
{ wiaCryptoContext, pidCryptoContext, pid, walletInstanceAttestation }
|
145
|
+
);
|
146
|
+
|
147
|
+
// Generate the DPoP context which will be used for the whole issuance flow
|
148
|
+
await regenerateCryptoKey(DPOP_KEYTAG); // Let's assume this function regenerates this ephemeral key for the DPoP
|
149
|
+
const dPopCryptoContext = createCryptoContextFor(DPOP_KEYTAG);
|
150
|
+
|
151
|
+
const { accessToken } = await Credential.Issuance.authorizeAccess(
|
152
|
+
issuerConf,
|
153
|
+
code,
|
154
|
+
clientId,
|
155
|
+
redirectUri,
|
156
|
+
codeVerifier,
|
157
|
+
{
|
158
|
+
walletInstanceAttestation,
|
159
|
+
wiaCryptoContext,
|
160
|
+
dPopCryptoContext,
|
161
|
+
appFetch,
|
162
|
+
}
|
163
|
+
);
|
164
|
+
|
165
|
+
// Obtain the credential
|
166
|
+
const { credential, format } = await Credential.Issuance.obtainCredential(
|
167
|
+
issuerConf,
|
168
|
+
accessToken,
|
169
|
+
clientId,
|
170
|
+
credentialDefinition,
|
171
|
+
{
|
172
|
+
credentialCryptoContext,
|
173
|
+
dPopCryptoContext,
|
174
|
+
appFetch,
|
175
|
+
}
|
176
|
+
);
|
177
|
+
|
178
|
+
// Parse and verify the credential. The ignoreMissingAttributes flag must be set to false or omitted in production.
|
179
|
+
const { parsedCredential } = await Credential.Issuance.verifyAndParseCredential(
|
180
|
+
issuerConf,
|
181
|
+
credential,
|
182
|
+
format,
|
183
|
+
{ credentialCryptoContext, ignoreMissingAttributes: true }
|
184
|
+
);
|
185
|
+
|
186
|
+
return {
|
187
|
+
parsedCredential,
|
188
|
+
credential,
|
189
|
+
keyTag: credentialKeyTag,
|
190
|
+
credentialType,
|
191
|
+
};
|
192
|
+
```
|
193
|
+
|
194
|
+
</details>
|
195
|
+
|
196
|
+
<details>
|
197
|
+
<summary>eID issuance flow</summary>
|
198
|
+
|
199
|
+
```ts
|
200
|
+
// Retrieve the integrity key tag from the store and create its context
|
201
|
+
const integrityKeyTag = "example"; // Let's assume this is the key tag used to create the wallet instance
|
202
|
+
const integrityContext = getIntegrityContext(integrityKeyTag);
|
203
|
+
|
204
|
+
// generate Key for Wallet Instance Attestation
|
205
|
+
// ensure the key esists befor starting the issuing process
|
206
|
+
await regenerateCryptoKey(WIA_KEYTAG); // Let's assume this function regenerates this ephemeral key
|
207
|
+
const wiaCryptoContext = createCryptoContextFor(WIA_KEYTAG);
|
208
|
+
|
209
|
+
const { WALLET_PROVIDER_BASE_URL, WALLET_EID_PROVIDER_BASE_URL, REDIRECT_URI } =
|
210
|
+
env; // Let's assume these are the environment variables
|
211
|
+
|
212
|
+
/**
|
213
|
+
* Obtains a new Wallet Instance Attestation.
|
214
|
+
* WARNING: The integrity context must be the same used when creating the Wallet Instance with the same keytag.
|
215
|
+
*/
|
216
|
+
const walletInstanceAttestation =
|
217
|
+
await WalletInstanceAttestation.getAttestation({
|
218
|
+
wiaCryptoContext,
|
219
|
+
integrityContext,
|
220
|
+
walletProviderBaseUrl: WALLET_PROVIDER_BASE_URL,
|
221
|
+
appFetch,
|
222
|
+
});
|
223
|
+
|
224
|
+
const idpHit = "https://example.com"; // Let's assume this is the IDP hint
|
225
|
+
|
226
|
+
const authorizationContext = idpHint.includes("servizicie")
|
227
|
+
? undefined
|
228
|
+
: {
|
229
|
+
authorize: openAuthenticationSession, // Let's assume this function opens the browser for the user to authenticate
|
230
|
+
};
|
231
|
+
/*
|
232
|
+
* Create credential crypto context for the PID
|
233
|
+
* WARNING: The eID keytag must be persisted and later used when requesting a credential which requires a eID presentation
|
234
|
+
*/
|
235
|
+
const credentialKeyTag = uuid.v4().toString();
|
236
|
+
await generate(credentialKeyTag);
|
237
|
+
const credentialCryptoContext = createCryptoContextFor(credentialKeyTag);
|
238
|
+
|
239
|
+
// Start the issuance flow
|
240
|
+
const startFlow: Credential.Issuance.StartFlow = () => ({
|
241
|
+
issuerUrl: WALLET_EID_PROVIDER_BASE_URL,
|
242
|
+
credentialType: "PersonIdentificationData",
|
243
|
+
appFetch,
|
244
|
+
});
|
245
|
+
|
246
|
+
const { issuerUrl } = startFlow();
|
247
|
+
|
248
|
+
// Evaluate issuer trust
|
249
|
+
const { issuerConf } = await Credential.Issuance.evaluateIssuerTrust(
|
250
|
+
issuerUrl,
|
251
|
+
{ appFetch }
|
252
|
+
);
|
253
|
+
|
254
|
+
// Start user authorization
|
255
|
+
const { issuerRequestUri, clientId, codeVerifier, credentialDefinition } =
|
256
|
+
await Credential.Issuance.startUserAuthorization(issuerConf, credentialType, {
|
257
|
+
walletInstanceAttestation,
|
258
|
+
redirectUri,
|
259
|
+
wiaCryptoContext,
|
260
|
+
appFetch,
|
261
|
+
});
|
262
|
+
|
263
|
+
// Complete the authroization process with query mode with the authorizationContext which opens the browser
|
264
|
+
const { code } =
|
265
|
+
await Credential.Issuance.completeUserAuthorizationWithQueryMode(
|
266
|
+
issuerRequestUri,
|
267
|
+
clientId,
|
268
|
+
issuerConf,
|
269
|
+
idpHint,
|
270
|
+
redirectUri,
|
271
|
+
authorizationContext
|
272
|
+
);
|
273
|
+
|
274
|
+
// Create DPoP context which will be used for the whole issuance flow
|
275
|
+
await regenerateCryptoKey(DPOP_KEYTAG);
|
276
|
+
const dPopCryptoContext = createCryptoContextFor(DPOP_KEYTAG);
|
277
|
+
|
278
|
+
const { accessToken } = await Credential.Issuance.authorizeAccess(
|
279
|
+
issuerConf,
|
280
|
+
code,
|
281
|
+
clientId,
|
282
|
+
redirectUri,
|
283
|
+
codeVerifier,
|
284
|
+
{
|
285
|
+
walletInstanceAttestation,
|
286
|
+
wiaCryptoContext,
|
287
|
+
dPopCryptoContext,
|
288
|
+
appFetch,
|
289
|
+
}
|
290
|
+
);
|
291
|
+
|
292
|
+
// Obtain che eID credential
|
293
|
+
const { credential, format } = await Credential.Issuance.obtainCredential(
|
294
|
+
issuerConf,
|
295
|
+
accessToken,
|
296
|
+
clientId,
|
297
|
+
credentialDefinition,
|
298
|
+
{
|
299
|
+
credentialCryptoContext,
|
300
|
+
dPopCryptoContext,
|
301
|
+
appFetch,
|
302
|
+
}
|
303
|
+
);
|
304
|
+
|
305
|
+
// Parse and verify the eID credential
|
306
|
+
const { parsedCredential } = await Credential.Issuance.verifyAndParseCredential(
|
307
|
+
issuerConf,
|
308
|
+
credential,
|
309
|
+
format,
|
310
|
+
{ credentialCryptoContext }
|
311
|
+
);
|
312
|
+
|
313
|
+
return {
|
314
|
+
parsedCredential,
|
315
|
+
credential,
|
316
|
+
keyTag: credentialKeyTag,
|
317
|
+
credentialType,
|
318
|
+
};
|
319
|
+
```
|
320
|
+
|
321
|
+
The result of this flow is a row credential and a parsed credential which must be stored securely in the wallet along with its crypto key.
|
322
|
+
|
323
|
+
</details>
|
@@ -0,0 +1,64 @@
|
|
1
|
+
# Credential Status Attestation
|
2
|
+
|
3
|
+
This flow is used to obtain a credential status attestation from its credential issuer. Each step in the flow is imported from the related file which is named with a sequential number.
|
4
|
+
The credential status attestation is a JWT which contains the credential status which indicates if the credential is valid or not.
|
5
|
+
The status attestation is supposed to be stored securely along with the credential. It has a limited lifetime and should be refreshed periodically according to the `exp` field in the JWT payload.
|
6
|
+
|
7
|
+
## Sequence Diagram
|
8
|
+
|
9
|
+
```mermaid
|
10
|
+
graph TD;
|
11
|
+
0[startFlow]
|
12
|
+
1[statusAttestation]
|
13
|
+
2[verifyAndParseStatusAttestation]
|
14
|
+
|
15
|
+
0 --> 1
|
16
|
+
1 --> 2
|
17
|
+
```
|
18
|
+
|
19
|
+
## Mapped results
|
20
|
+
|
21
|
+
### 404 Not Found (StatusAttestationInvalid)
|
22
|
+
|
23
|
+
A `404 Not Found` response is returned by the credential issuer when the status attestation is invalid.
|
24
|
+
|
25
|
+
## Example
|
26
|
+
|
27
|
+
<details>
|
28
|
+
<summary>Credential status attestation flow</summary>
|
29
|
+
|
30
|
+
```ts
|
31
|
+
// Start the issuance flow
|
32
|
+
const credentialIssuerUrl = "https://issuer.example.com";
|
33
|
+
const startFlow: Credential.Status.StartFlow = () => ({
|
34
|
+
issuerUrl: credentialIssuerUrl, // Let's assum
|
35
|
+
});
|
36
|
+
|
37
|
+
const { issuerUrl } = startFlow();
|
38
|
+
|
39
|
+
// Evaluate issuer trust
|
40
|
+
const { issuerConf } = await Credential.Status.evaluateIssuerTrust(issuerUrl);
|
41
|
+
|
42
|
+
// Get the credential attestation
|
43
|
+
const res = await Credential.Status.statusAttestation(
|
44
|
+
issuerConf,
|
45
|
+
credential,
|
46
|
+
credentialCryptoContext
|
47
|
+
);
|
48
|
+
|
49
|
+
// Verify and parse the status attestation
|
50
|
+
const { parsedStatusAttestation } =
|
51
|
+
await Credential.Status.verifyAndParseStatusAttestation(
|
52
|
+
issuerConf,
|
53
|
+
res.statusAttestation,
|
54
|
+
{ credentialCryptoContext }
|
55
|
+
);
|
56
|
+
|
57
|
+
return {
|
58
|
+
statusAttestation: res.statusAttestation,
|
59
|
+
parsedStatusAttestation,
|
60
|
+
credentialType,
|
61
|
+
};
|
62
|
+
```
|
63
|
+
|
64
|
+
</details>
|
package/src/utils/errors.ts
CHANGED
@@ -462,3 +462,21 @@ export class CredentialRequestError extends IoWalletError {
|
|
462
462
|
this.reason = reason;
|
463
463
|
}
|
464
464
|
}
|
465
|
+
|
466
|
+
/**
|
467
|
+
* Error subclass thrown when a credential cannot be issued immediately because it follows the async flow.
|
468
|
+
*/
|
469
|
+
export class CredentialIssuingNotSynchronousError extends IoWalletError {
|
470
|
+
static get code(): "CREDENTIAL_ISSUING_NOT_SYNCHRONOUS_ERROR" {
|
471
|
+
return "CREDENTIAL_ISSUING_NOT_SYNCHRONOUS_ERROR";
|
472
|
+
}
|
473
|
+
|
474
|
+
code = "CREDENTIAL_ISSUING_NOT_SYNCHRONOUS_ERROR";
|
475
|
+
|
476
|
+
reason: string;
|
477
|
+
|
478
|
+
constructor(message: string, reason: string = "unspecified") {
|
479
|
+
super(serializeAttrs({ message, reason }));
|
480
|
+
this.reason = reason;
|
481
|
+
}
|
482
|
+
}
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# Wallet Instance
|
2
|
+
|
3
|
+
This flow which consists of a single step, is used to create a wallet instance. The wallet provider must implement its endpoints based on the OpenAPI specification provided in the [wallet-instance.yaml](../../openapi/wallet-provider.yaml) file.
|
4
|
+
A service that is responsible for ensuring the integrity of the device where the app is running is required and it's supposed to use [Google Play Integrity API](https://developer.android.com/google/play/integrity/overview) and [Key Attestation](https://developer.android.com/privacy-and-security/security-key-attestation) on Android, [DCAppAttestService](https://developer.apple.com/documentation/devicecheck/establishing-your-app-s-integrity) on iOS.
|
5
|
+
The suggested way to implement this service is to use [io-react-native-integrity](https://github.com/pagopa/io-react-native-integrity) by providing an [IntegrityContext](../utils/integrity.ts) object.
|
6
|
+
An example is provided as follows:
|
7
|
+
|
8
|
+
```ts
|
9
|
+
// Get env
|
10
|
+
const { GOOGLE_CLOUD_PROJECT_NUMBER, WALLET_PROVIDER_BASE_URL } = env; // Let's assume env is an object containing the environment variables
|
11
|
+
|
12
|
+
const googleCloudProjectNumber = isAndroid
|
13
|
+
? GOOGLE_CLOUD_PROJECT_NUMBER
|
14
|
+
: undefined;
|
15
|
+
|
16
|
+
await ensureIntegrityServiceIsReady(googleCloudProjectNumber); // Required by io-react-native-integrity to ensure the service is ready
|
17
|
+
const integrityKeyTag = await generateIntegrityHardwareKeyTag();
|
18
|
+
const integrityContext = getIntegrityContext(integrityKeyTag); // This function is supposed to return an object as required by IntegrityContext.
|
19
|
+
|
20
|
+
await WalletInstance.createWalletInstance({
|
21
|
+
integrityContext,
|
22
|
+
walletProviderBaseUrl: WALLET_PROVIDER_BASE_URL,
|
23
|
+
appFetch,
|
24
|
+
});
|
25
|
+
|
26
|
+
return integrityKeyTag;
|
27
|
+
```
|
28
|
+
|
29
|
+
The returned `integrityKeyTag` is supposed to be stored and used to verify the integrity of the device in the future when using an `IntegrityContext` object. It must be regenerated if another wallet instance is created.
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# Wallet Instance Attestation
|
2
|
+
|
3
|
+
This flow consists of a single step and is used to obtain a Wallet Instance Attestation. The wallet provider must implement its endpoints based on the OpenAPI specification provided in the [wallet-instance.yaml](../../openapi/wallet-provider.yaml) file.
|
4
|
+
In order to require a status attestation the consumer application must provide:
|
5
|
+
|
6
|
+
- `wiaCryptoContext` object that is used to sign the attestation request. The key must be generated before creating the crypto context;
|
7
|
+
- `integrityContext` object that is used to verify the integrity of the device where the app is running. The key tag must be the same used when creating the Wallet Instance;
|
8
|
+
|
9
|
+
```ts
|
10
|
+
// Retrieve the integrity key tag from the store and create its context
|
11
|
+
const integrityKeyTag = "example"; // Let's assume this is the same key used when creating the Wallet Instance
|
12
|
+
const integrityContext = getIntegrityContext(integrityKeyTag);
|
13
|
+
|
14
|
+
// generate Key for Wallet Instance Attestation
|
15
|
+
// ensure the key esists befor starting the issuing process
|
16
|
+
await regenerateCryptoKey(WIA_KEYTAG); // Let's assume WI_KEYTAG is a constant string and regenerateCryptoKey is a function that regenerates the key each time it is called
|
17
|
+
const wiaCryptoContext = createCryptoContextFor(WIA_KEYTAG);
|
18
|
+
|
19
|
+
// Get env URLs
|
20
|
+
const { WALLET_PROVIDER_BASE_URL } = env; // Let's assume env is an object containing the environment variables
|
21
|
+
|
22
|
+
/**
|
23
|
+
* Obtains a new Wallet Instance Attestation.
|
24
|
+
* WARNING: The integrity context must be the same used when creating the Wallet Instance with the same keytag.
|
25
|
+
*/
|
26
|
+
const issuedAttestation = await WalletInstanceAttestation.getAttestation({
|
27
|
+
wiaCryptoContext,
|
28
|
+
integrityContext,
|
29
|
+
walletProviderBaseUrl: WALLET_PROVIDER_BASE_URL,
|
30
|
+
appFetch,
|
31
|
+
});
|
32
|
+
return issuedAttestation;
|
33
|
+
```
|
34
|
+
|
35
|
+
The returned `issuedAttestation` is supposed to be stored and used for any future operation that requires a Wallet Instance Attestation. The wallet attestation has a limited validity and must be regenerated when it expires.
|