@kryptos_connect/mobile-sdk 1.0.6-dev.1 → 2.0.1-dev.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/README.md +163 -539
- package/dist/index.cjs +367 -0
- package/dist/index.d.cts +44 -0
- package/dist/index.d.ts +36 -72
- package/dist/index.js +311 -4781
- package/package.json +18 -78
- package/LICENSE +0 -22
- package/dist/index.d.mts +0 -80
- package/dist/index.mjs +0 -4832
package/README.md
CHANGED
|
@@ -1,625 +1,249 @@
|
|
|
1
1
|
# @kryptos_connect/mobile-sdk
|
|
2
2
|
|
|
3
|
-
Kryptos Connect Mobile SDK for React Native – works with
|
|
3
|
+
Kryptos Connect Mobile SDK for React Native – works with Expo and React Native CLI. Seamless Kryptos integration with built-in authentication, theme support, and wallet connectivity. Connect your users to the complete Web3 finance ecosystem with support for 5000+ DeFi protocols, 200+ exchanges and wallets, and 100+ blockchains.
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
7
|
-
### Using npm
|
|
8
|
-
|
|
9
|
-
```bash
|
|
10
|
-
npm install @kryptos_connect/mobile-sdk react-native-svg
|
|
11
|
-
```
|
|
12
|
-
|
|
13
|
-
### Using yarn
|
|
14
|
-
|
|
15
7
|
```bash
|
|
16
|
-
|
|
8
|
+
npm install @kryptos_connect/mobile-sdk react-native-webview
|
|
17
9
|
```
|
|
18
10
|
|
|
19
|
-
### For Expo
|
|
20
|
-
|
|
21
|
-
```bash
|
|
22
|
-
npx expo install @kryptos_connect/mobile-sdk react-native-svg
|
|
23
|
-
```
|
|
24
|
-
|
|
25
|
-
### iOS (React Native CLI only)
|
|
26
|
-
|
|
27
11
|
```bash
|
|
12
|
+
# iOS — install native pods
|
|
28
13
|
cd ios && pod install
|
|
29
14
|
```
|
|
30
15
|
|
|
31
16
|
## Prerequisites
|
|
32
17
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
1. **Client ID**: Obtain from [Kryptos Developer Portal](https://dashboard.kryptos.io)
|
|
36
|
-
2. **WalletConnect Project ID**: Get from [WalletConnect Cloud](https://cloud.walletconnect.com) (optional, for wallet connectivity)
|
|
18
|
+
- **Client ID** — from the [Kryptos Developer Portal](https://dashboard.kryptos.io/)
|
|
19
|
+
- **WalletConnect Project ID** — from [WalletConnect Cloud](https://cloud.walletconnect.com) _(optional)_
|
|
37
20
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
For Expo or bare React Native, install the core WalletConnect/AppKit deps together:
|
|
41
|
-
|
|
42
|
-
```bash
|
|
43
|
-
npx expo install @reown/appkit-react-native @react-native-async-storage/async-storage react-native-get-random-values react-native-svg @react-native-community/netinfo @walletconnect/react-native-compat react-native-safe-area-context expo-application
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
## Platform Setup
|
|
47
|
-
|
|
48
|
-
### Expo (managed or prebuild)
|
|
49
|
-
|
|
50
|
-
- Install the required peer deps (AppKit + WalletConnect) in one go:
|
|
21
|
+
---
|
|
51
22
|
|
|
52
|
-
|
|
53
|
-
npx expo install @kryptos_connect/mobile-sdk react-native-svg @react-native-async-storage/async-storage @react-native-community/netinfo react-native-get-random-values @walletconnect/react-native-compat @reown/appkit-react-native @reown/appkit-ethers-react-native expo-application
|
|
54
|
-
```
|
|
23
|
+
## Quick start
|
|
55
24
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
// babel.config.js
|
|
59
|
-
module.exports = function (api) {
|
|
60
|
-
api.cache(true);
|
|
61
|
-
return {
|
|
62
|
-
presets: [["babel-preset-expo", { unstable_transformImportMeta: true }]],
|
|
63
|
-
};
|
|
64
|
-
};
|
|
65
|
-
```
|
|
25
|
+
```tsx
|
|
26
|
+
import { KryptosConnect, KryptosConnectButton } from "@kryptos_connect/mobile-sdk";
|
|
66
27
|
|
|
67
|
-
|
|
28
|
+
// 1. Initialize once (or on every render to keep config in sync)
|
|
29
|
+
KryptosConnect.init({
|
|
30
|
+
clientId: "your-client-id",
|
|
31
|
+
appName: "My App",
|
|
32
|
+
appLogo: "https://yourapp.com/logo.png",
|
|
33
|
+
baseUrl: "https://connect-api.kryptos.io",
|
|
34
|
+
theme: "light", // "light" | "dark" | "auto"
|
|
35
|
+
language: "en", // "en" | "fr" | "de" | "pt" | "sv" | "es" | "pl" | "it"
|
|
36
|
+
authMethods: ["email", "anonymous"],
|
|
37
|
+
});
|
|
68
38
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
39
|
+
// 2. Drop in the button
|
|
40
|
+
<KryptosConnectButton
|
|
41
|
+
generateLinkToken={generateLinkToken}
|
|
42
|
+
onConnectSuccess={(consent) => console.log(consent.public_token)}
|
|
43
|
+
onConnectError={(err) => console.error(err)}
|
|
44
|
+
buttonLabel="Connect Kryptos"
|
|
45
|
+
buttonHeight={52}
|
|
46
|
+
/>;
|
|
47
|
+
```
|
|
74
48
|
|
|
75
|
-
|
|
49
|
+
---
|
|
76
50
|
|
|
77
|
-
|
|
51
|
+
## Full example
|
|
78
52
|
|
|
79
53
|
```tsx
|
|
80
|
-
import {
|
|
54
|
+
import { KryptosConnect, KryptosConnectButton } from "@kryptos_connect/mobile-sdk";
|
|
55
|
+
import { useState } from "react";
|
|
81
56
|
|
|
82
|
-
const
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
theme: "light", // or 'dark'
|
|
87
|
-
walletConnectProjectId: "your-walletconnect-project-id",
|
|
88
|
-
};
|
|
57
|
+
const BASE_URL = "https://connect-api.kryptos.io";
|
|
58
|
+
const CLIENT_ID = "your-client-id";
|
|
59
|
+
const CLIENT_SECRET = "your-client-secret"; // keep server-side in production
|
|
60
|
+
const SCOPES = "openid profile offline_access email portfolios:read integrations:read";
|
|
89
61
|
|
|
90
62
|
export default function App() {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
| Property | Type | Required | Description |
|
|
102
|
-
| ------------------------ | ------------------------------------------ | -------- | --------------------------------------------------------------------------- |
|
|
103
|
-
| `appName` | `string` | Yes | Your application name |
|
|
104
|
-
| `appLogo` | `React.ReactNode \| string \| ImageSource` | No | Your app logo (URL, `require()`, or React Native image source) |
|
|
105
|
-
| `clientId` | `string` | Yes | Your Kryptos client ID |
|
|
106
|
-
| `theme` | `"light" \| "dark"` | No | Default theme mode (defaults to `"light"` if not set) |
|
|
107
|
-
| `walletConnectProjectId` | `string` | No | Your WalletConnect project ID (enables built-in AppKit / wallet connection) |
|
|
108
|
-
|
|
109
|
-
### 2. Add the Connect Button
|
|
63
|
+
const [accessToken, setAccessToken] = useState(null);
|
|
64
|
+
|
|
65
|
+
KryptosConnect.init({
|
|
66
|
+
clientId: CLIENT_ID,
|
|
67
|
+
appName: "My App",
|
|
68
|
+
baseUrl: BASE_URL,
|
|
69
|
+
theme: "light",
|
|
70
|
+
language: "en",
|
|
71
|
+
authMethods: ["email", "anonymous"],
|
|
72
|
+
});
|
|
110
73
|
|
|
111
|
-
|
|
112
|
-
|
|
74
|
+
async function generateLinkToken(existingAccessToken?: string | null) {
|
|
75
|
+
const body: Record<string, unknown> = { scopes: SCOPES };
|
|
76
|
+
if (existingAccessToken) body.access_token = existingAccessToken;
|
|
113
77
|
|
|
114
|
-
|
|
115
|
-
const generateLinkToken = async () => {
|
|
116
|
-
// Call your backend API to generate a link token
|
|
117
|
-
const response = await fetch("https://your-api.com/generate-link-token", {
|
|
78
|
+
const res = await fetch(`${BASE_URL}/link-token`, {
|
|
118
79
|
method: "POST",
|
|
119
80
|
headers: {
|
|
120
81
|
"Content-Type": "application/json",
|
|
82
|
+
"X-Client-Id": CLIENT_ID,
|
|
83
|
+
"X-Client-Secret": CLIENT_SECRET,
|
|
121
84
|
},
|
|
85
|
+
body: JSON.stringify(body),
|
|
86
|
+
});
|
|
87
|
+
const data = await res.json();
|
|
88
|
+
return { link_token: data.data.link_token, isAuthorized: !!existingAccessToken };
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
async function handleSuccess(consent) {
|
|
92
|
+
if (!consent) return; // re-auth — no new token
|
|
93
|
+
const res = await fetch(`${BASE_URL}/token/exchange`, {
|
|
94
|
+
method: "POST",
|
|
95
|
+
headers: { "Content-Type": "application/json" },
|
|
122
96
|
body: JSON.stringify({
|
|
123
|
-
|
|
124
|
-
|
|
97
|
+
public_token: consent.public_token,
|
|
98
|
+
client_id: CLIENT_ID,
|
|
99
|
+
client_secret: CLIENT_SECRET,
|
|
125
100
|
}),
|
|
126
101
|
});
|
|
127
|
-
const data = await
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
link_token: data.link_token,
|
|
131
|
-
isAuthorized: data.isAuthorized, // pass true if access_token was provided
|
|
132
|
-
};
|
|
133
|
-
};
|
|
134
|
-
|
|
135
|
-
const handleSuccess = (userConsent) => {
|
|
136
|
-
console.log("Connection successful!", userConsent);
|
|
137
|
-
// For new users, exchange the public token for an access token
|
|
138
|
-
// For authorized users, userConsent might be null
|
|
139
|
-
if (userConsent?.public_token) {
|
|
140
|
-
exchangePublicToken(userConsent.public_token);
|
|
141
|
-
}
|
|
142
|
-
};
|
|
143
|
-
|
|
144
|
-
const handleError = (error) => {
|
|
145
|
-
console.error("Connection failed:", error);
|
|
146
|
-
};
|
|
147
|
-
|
|
148
|
-
return (
|
|
149
|
-
<KryptosConnectButton
|
|
150
|
-
generateLinkToken={generateLinkToken}
|
|
151
|
-
onSuccess={handleSuccess}
|
|
152
|
-
onError={handleError}
|
|
153
|
-
/>
|
|
154
|
-
);
|
|
155
|
-
}
|
|
156
|
-
```
|
|
157
|
-
|
|
158
|
-
#### User Flow Variations
|
|
159
|
-
|
|
160
|
-
The SDK automatically handles two different user flows based on the `isAuthorized` flag returned from `generateLinkToken`:
|
|
161
|
-
|
|
162
|
-
**Flow 1: New User** (`isAuthorized: false` or undefined)
|
|
163
|
-
|
|
164
|
-
```
|
|
165
|
-
INIT → Connect → INTEGRATION → STATUS
|
|
166
|
-
```
|
|
167
|
-
|
|
168
|
-
- **INIT (Connect)**: Fetches link token and initializes the session & an account is created for them on the backend
|
|
169
|
-
- **INTEGRATION**: User selects and connects integrations (wallets, exchanges, blockchains)
|
|
170
|
-
- **STATUS**: Success or error result; returns `public_token` in `onSuccess` when consent is given, or `null` when user was already authorized
|
|
171
|
-
|
|
172
|
-
**Flow 2: Authenticated User** (`isAuthorized: true`)
|
|
173
|
-
|
|
174
|
-
```
|
|
175
|
-
INIT → INTEGRATION → STATUS
|
|
176
|
-
```
|
|
177
|
-
|
|
178
|
-
- Skips Connect (an account already exists for the user on the backend)
|
|
179
|
-
- User directly selects integrations
|
|
180
|
-
- Returns `null` in `onSuccess` callback (no new token needed)
|
|
181
|
-
|
|
182
|
-
### Implementation Example
|
|
183
|
-
|
|
184
|
-
```tsx
|
|
185
|
-
const generateLinkToken = async () => {
|
|
186
|
-
const user = getCurrentUser(); // Your auth logic
|
|
187
|
-
|
|
188
|
-
const response = await fetch("/api/kryptos/create-link-token", {
|
|
189
|
-
method: "POST",
|
|
190
|
-
headers: {
|
|
191
|
-
"Content-Type": "application/json",
|
|
192
|
-
},
|
|
193
|
-
body: JSON.stringify({
|
|
194
|
-
// Include access_token if user is logged in
|
|
195
|
-
access_token: user?.kryptosAccessToken || undefined,
|
|
196
|
-
}),
|
|
197
|
-
});
|
|
198
|
-
|
|
199
|
-
const data = await response.json();
|
|
200
|
-
|
|
201
|
-
return {
|
|
202
|
-
link_token: data.link_token,
|
|
203
|
-
// isAuthorized will be true if access_token was valid
|
|
204
|
-
isAuthorized: !!user?.kryptosAccessToken,
|
|
205
|
-
};
|
|
206
|
-
};
|
|
207
|
-
```
|
|
208
|
-
|
|
209
|
-
## WalletConnect / Reown AppKit configuration
|
|
210
|
-
|
|
211
|
-
Passing a `walletConnectProjectId` to `KryptosConnectProvider` enables the built-in AppKit (WalletConnect v2) flow used by the `WalletConnectComponent`:
|
|
212
|
-
|
|
213
|
-
```tsx
|
|
214
|
-
import "@walletconnect/react-native-compat";
|
|
215
|
-
import "react-native-get-random-values";
|
|
216
|
-
import { KryptosConnectProvider } from "@kryptos_connect/mobile-sdk";
|
|
217
|
-
|
|
218
|
-
const config = {
|
|
219
|
-
appName: "Your App",
|
|
220
|
-
appLogo: "https://your-logo.png",
|
|
221
|
-
clientId: "<kryptos-client-id>",
|
|
222
|
-
walletConnectProjectId: "<walletconnect-cloud-project-id>",
|
|
223
|
-
};
|
|
102
|
+
const data = await res.json();
|
|
103
|
+
setAccessToken(data.data.access_token);
|
|
104
|
+
}
|
|
224
105
|
|
|
225
|
-
export default function App() {
|
|
226
106
|
return (
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
107
|
+
<>
|
|
108
|
+
{/* Default button */}
|
|
109
|
+
<KryptosConnectButton
|
|
110
|
+
generateLinkToken={() => generateLinkToken()}
|
|
111
|
+
onConnectSuccess={handleSuccess}
|
|
112
|
+
onConnectError={(err) => console.error(err)}
|
|
113
|
+
buttonLabel="Link Kryptos Account"
|
|
114
|
+
buttonHeight={52}
|
|
115
|
+
/>
|
|
116
|
+
|
|
117
|
+
{/* Pre-select a specific integration with custom style */}
|
|
118
|
+
<KryptosConnectButton
|
|
119
|
+
generateLinkToken={() => generateLinkToken()}
|
|
120
|
+
onConnectSuccess={handleSuccess}
|
|
121
|
+
onConnectError={(err) => console.error(err)}
|
|
122
|
+
integrationName="coinbase"
|
|
123
|
+
buttonLabel="Connect Coinbase"
|
|
124
|
+
buttonHeight={48}
|
|
125
|
+
style={{ borderRadius: 10, backgroundColor: "#0052FF" }}
|
|
126
|
+
/>
|
|
127
|
+
|
|
128
|
+
{/* Re-authorize with stored access token */}
|
|
129
|
+
{accessToken && (
|
|
130
|
+
<KryptosConnectButton
|
|
131
|
+
generateLinkToken={() => generateLinkToken(accessToken)}
|
|
132
|
+
onConnectSuccess={handleSuccess}
|
|
133
|
+
onConnectError={(err) => console.error(err)}
|
|
134
|
+
buttonLabel="Continue with Access Token"
|
|
135
|
+
buttonHeight={52}
|
|
136
|
+
/>
|
|
137
|
+
)}
|
|
138
|
+
</>
|
|
230
139
|
);
|
|
231
140
|
}
|
|
232
141
|
```
|
|
233
142
|
|
|
234
|
-
|
|
143
|
+
---
|
|
235
144
|
|
|
236
|
-
|
|
145
|
+
## KryptosConnectButton props
|
|
237
146
|
|
|
238
|
-
|
|
147
|
+
| Prop | Type | Required | Description |
|
|
148
|
+
| ------------------- | --------------------------------------------------------------- | -------- | --------------------------------------------------------------------------------- |
|
|
149
|
+
| `generateLinkToken` | `() => Promise<{ link_token: string; isAuthorized?: boolean }>` | Yes | Called on press. Return `isAuthorized: true` to skip auth for existing users. |
|
|
150
|
+
| `onConnectSuccess` | `(data: UserConsent \| null) => void` | Yes | Called on success. `data` is `null` when `isAuthorized` was `true`. |
|
|
151
|
+
| `onConnectError` | `(error: Error) => void` | Yes | Called on error or dismissal. |
|
|
152
|
+
| `integrationName` | `string` | No | Skip the integration list and open a specific integration directly. |
|
|
153
|
+
| `buttonLabel` | `string` | No | Button text. |
|
|
154
|
+
| `buttonHeight` | `number` | No | Button height in dp. Default `56`. |
|
|
155
|
+
| `extraConfig` | `Record<string, unknown>` | No | Per-button config overrides, merged onto the global config. |
|
|
156
|
+
| `style` | `StyleProp<ViewStyle>` | No | Style for the button. `backgroundColor` overrides `--kc-primary` for that button. |
|
|
239
157
|
|
|
240
|
-
|
|
241
|
-
import { KryptosConnectProvider } from "@kryptos_connect/mobile-sdk";
|
|
242
|
-
|
|
243
|
-
// Development Environment
|
|
244
|
-
const devConfig = {
|
|
245
|
-
appName: "Your App",
|
|
246
|
-
clientId: "your-client-id",
|
|
247
|
-
theme: "light",
|
|
248
|
-
walletConnectProjectId: "your-project-id",
|
|
249
|
-
};
|
|
158
|
+
---
|
|
250
159
|
|
|
251
|
-
|
|
252
|
-
const prodConfig = {
|
|
253
|
-
appName: "Your App",
|
|
254
|
-
clientId: "your-client-id",
|
|
255
|
-
theme: "light",
|
|
256
|
-
walletConnectProjectId: "your-project-id",
|
|
257
|
-
};
|
|
160
|
+
## KryptosConnect.init config
|
|
258
161
|
|
|
259
|
-
|
|
260
|
-
|
|
162
|
+
| Key | Type | Required | Description |
|
|
163
|
+
| ------------------------ | ----------------------------- | -------- | -------------------------------------------------------------------------------------------------------------------------- |
|
|
164
|
+
| `appName` | `string` | Yes | Displayed in the connect UI header. |
|
|
165
|
+
| `clientId` | `string` | No | Your Kryptos client ID. |
|
|
166
|
+
| `appLogo` | `string` | No | URI to your app logo shown in the connect UI. |
|
|
167
|
+
| `walletConnectProjectId` | `string` | No | Required if using WalletConnect. |
|
|
168
|
+
| `theme` | `"light" \| "dark" \| "auto"` | No | UI theme. Default `"light"`. |
|
|
169
|
+
| `language` | `string` | No | UI language. Supported: `en fr de pt sv es pl it`. |
|
|
170
|
+
| `authMethods` | `("email" \| "anonymous")[]` | No | Auth methods shown. Default: both. |
|
|
171
|
+
| `cssVars` | `Record<string, string>` | No | Override `--kc-*` CSS variables in the connect UI. `--kc-primary` and `--kc-primary-text` also apply to the native button. |
|
|
261
172
|
|
|
262
|
-
|
|
263
|
-
<KryptosConnectProvider config={config}>
|
|
264
|
-
<YourApp />
|
|
265
|
-
</KryptosConnectProvider>
|
|
266
|
-
);
|
|
267
|
-
}
|
|
268
|
-
```
|
|
173
|
+
---
|
|
269
174
|
|
|
270
|
-
|
|
175
|
+
## Customization
|
|
271
176
|
|
|
272
|
-
|
|
177
|
+
Pass `cssVars` to theme the connect UI and native button colors:
|
|
273
178
|
|
|
274
179
|
```tsx
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
generateLinkToken={generateLinkToken}
|
|
282
|
-
onSuccess={handleSuccess}
|
|
283
|
-
onError={handleError}
|
|
284
|
-
>
|
|
285
|
-
<View style={styles.customButton}>
|
|
286
|
-
<Text style={styles.customText}>🔐 Connect Your Wallet</Text>
|
|
287
|
-
</View>
|
|
288
|
-
</KryptosConnectButton>
|
|
289
|
-
);
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
const styles = StyleSheet.create({
|
|
293
|
-
customButton: {
|
|
294
|
-
backgroundColor: "#00C693",
|
|
295
|
-
paddingVertical: 12,
|
|
296
|
-
paddingHorizontal: 24,
|
|
297
|
-
borderRadius: 8,
|
|
298
|
-
alignItems: "center",
|
|
299
|
-
},
|
|
300
|
-
customText: {
|
|
301
|
-
color: "#FFFFFF",
|
|
302
|
-
fontSize: 16,
|
|
303
|
-
fontWeight: "600",
|
|
180
|
+
KryptosConnect.init({
|
|
181
|
+
cssVars: {
|
|
182
|
+
"--kc-primary": "#8b5cf6",
|
|
183
|
+
"--kc-primary-hover": "#7c3aed",
|
|
184
|
+
"--kc-primary-text": "#ffffff",
|
|
185
|
+
"--kc-primary-light": "#ede9fe",
|
|
304
186
|
},
|
|
305
187
|
});
|
|
306
188
|
```
|
|
307
189
|
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
You can use the `integrationName` prop to direct users to a specific integration, bypassing the general integration selection. Useful for dedicated buttons for specific exchanges or wallets.
|
|
311
|
-
|
|
312
|
-
**Getting supported integration IDs:** Fetch from the public Kryptos API:
|
|
313
|
-
|
|
314
|
-
```bash
|
|
315
|
-
GET {BASE_URL}/integrations/public/list
|
|
316
|
-
```
|
|
317
|
-
|
|
318
|
-
**Usage example:**
|
|
190
|
+
To override colors on a per-button basis, use the `style` prop:
|
|
319
191
|
|
|
320
192
|
```tsx
|
|
321
|
-
// Direct connection to a specific integration (e.g. Binance)
|
|
322
|
-
<KryptosConnectButton
|
|
323
|
-
generateLinkToken={generateLinkToken}
|
|
324
|
-
integrationName="binance"
|
|
325
|
-
onSuccess={(userConsent) => {
|
|
326
|
-
console.log("Binance connected:", userConsent);
|
|
327
|
-
}}
|
|
328
|
-
>
|
|
329
|
-
Connect Binance Account
|
|
330
|
-
</KryptosConnectButton>
|
|
331
|
-
|
|
332
|
-
// Default button text when integrationName is set: "Connect {Integration} Account"
|
|
333
193
|
<KryptosConnectButton
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
onSuccess={(userConsent) => console.log("MetaMask connected:", userConsent)}
|
|
194
|
+
style={{ backgroundColor: "#0052FF", borderRadius: 10 }}
|
|
195
|
+
...
|
|
337
196
|
/>
|
|
338
197
|
```
|
|
339
198
|
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
## API Reference
|
|
343
|
-
|
|
344
|
-
### KryptosConnectProvider
|
|
345
|
-
|
|
346
|
-
The provider component that wraps your app and provides the Kryptos context.
|
|
347
|
-
|
|
348
|
-
#### Props
|
|
199
|
+
---
|
|
349
200
|
|
|
350
|
-
|
|
351
|
-
| ---------- | --------------- | -------- | -------------------- |
|
|
352
|
-
| `config` | `KryptosConfig` | Yes | Configuration object |
|
|
353
|
-
| `children` | `ReactNode` | Yes | Child components |
|
|
201
|
+
## User flows
|
|
354
202
|
|
|
355
|
-
|
|
203
|
+
**New user** — `generateLinkToken` returns `isAuthorized: false` (default):
|
|
356
204
|
|
|
357
|
-
```typescript
|
|
358
|
-
type KryptosConfig = {
|
|
359
|
-
appName: string; // Your app name
|
|
360
|
-
appLogo?: ReactNode | string | ImageSourcePropType; // Logo URL, React Native Image source, or require()
|
|
361
|
-
theme?: "light" | "dark"; // Theme mode (default: 'light')
|
|
362
|
-
clientId: string; // Your Kryptos client ID
|
|
363
|
-
walletConnectProjectId?: string; // Optional WalletConnect project ID
|
|
364
|
-
};
|
|
365
205
|
```
|
|
366
|
-
|
|
367
|
-
### KryptosConnectButton
|
|
368
|
-
|
|
369
|
-
The main button component that triggers the connection flow.
|
|
370
|
-
|
|
371
|
-
#### Props
|
|
372
|
-
|
|
373
|
-
| Prop | Type | Required | Description |
|
|
374
|
-
| ------------------- | --------------------------------------------------------------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
375
|
-
| `generateLinkToken` | `() => Promise<{ link_token: string; isAuthorized?: boolean }>` | Yes | Function that returns link token and authorization status. `isAuthorized: true` indicates the user is already authorized (consent API may be skipped; `onSuccess` receives `null`) |
|
|
376
|
-
| `onSuccess` | `(data: UserConsent \| null) => void` | No | Callback invoked when connection succeeds. Receives `public_token` for new users, `null` for authorized users |
|
|
377
|
-
| `onError` | `(error?: Error) => void` | No | Callback invoked when connection fails |
|
|
378
|
-
| `integrationName` | `string` | No | Integration ID from the supported providers list. When provided, skips the integration list and goes directly to that integration |
|
|
379
|
-
| `children` | `ReactNode` | No | Custom button content. Defaults to "Connect With Kryptos", or "Connect {Integration} Account" when `integrationName` is set |
|
|
380
|
-
| `style` | `ViewStyle` | No | Custom button container style |
|
|
381
|
-
| `textStyle` | `TextStyle` | No | Custom button text style |
|
|
382
|
-
|
|
383
|
-
#### TypeScript Types
|
|
384
|
-
|
|
385
|
-
```typescript
|
|
386
|
-
interface KryptosConnectButtonProps {
|
|
387
|
-
generateLinkToken: () => Promise<{
|
|
388
|
-
link_token: string;
|
|
389
|
-
isAuthorized?: boolean;
|
|
390
|
-
}>;
|
|
391
|
-
onSuccess?: (data: UserConsent | null) => void;
|
|
392
|
-
onError?: (error?: Error) => void;
|
|
393
|
-
integrationName?: string; // Integration ID from the supported providers list
|
|
394
|
-
children?: ReactNode;
|
|
395
|
-
style?: ViewStyle;
|
|
396
|
-
textStyle?: TextStyle;
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
interface UserConsent {
|
|
400
|
-
public_token: string;
|
|
401
|
-
// Additional consent data
|
|
402
|
-
}
|
|
403
|
-
|
|
404
|
-
// Note: onSuccess receives:
|
|
405
|
-
// - UserConsent with public_token for new users (isAuthorized: false)
|
|
406
|
-
// - null for authenticated users (isAuthorized: true)
|
|
206
|
+
press → AUTH → INTEGRATION → onConnectSuccess({ public_token })
|
|
407
207
|
```
|
|
408
208
|
|
|
409
|
-
|
|
209
|
+
Exchange `public_token` server-side for a long-lived `access_token`.
|
|
410
210
|
|
|
411
|
-
|
|
211
|
+
**Returning user** — pass stored `access_token` in the link-token request body and return `isAuthorized: true`:
|
|
412
212
|
|
|
413
|
-
```typescript
|
|
414
|
-
import type {
|
|
415
|
-
KryptosConnectButtonProps,
|
|
416
|
-
KryptosConfig,
|
|
417
|
-
UserConsent,
|
|
418
|
-
} from "@kryptos_connect/mobile-sdk";
|
|
419
213
|
```
|
|
420
|
-
|
|
421
|
-
## Backend Integration
|
|
422
|
-
|
|
423
|
-
You need to implement two backend endpoints. The same API is used for web and mobile.
|
|
424
|
-
|
|
425
|
-
### Base URLs
|
|
426
|
-
|
|
427
|
-
| Environment | URL |
|
|
428
|
-
| -------------- | -------------------------------- |
|
|
429
|
-
| **Production** | `https://connect-api.kryptos.io` |
|
|
430
|
-
|
|
431
|
-
### 1. Create Link Token
|
|
432
|
-
|
|
433
|
-
A link token can be created in two ways: to authenticate an existing user or to create a new session.
|
|
434
|
-
|
|
435
|
-
| Approach | When to use |
|
|
436
|
-
| -------- | -------------------------------- |
|
|
437
|
-
| Option A | New user, no access token |
|
|
438
|
-
| Option B | Returning user, has access token |
|
|
439
|
-
|
|
440
|
-
#### Option A: Without Access Token (New/Anonymous User)
|
|
441
|
-
|
|
442
|
-
Use this approach for **new users** (no access token):
|
|
443
|
-
|
|
444
|
-
```javascript
|
|
445
|
-
// Example: Node.js/Express
|
|
446
|
-
app.post("/api/kryptos/create-link-token", async (req, res) => {
|
|
447
|
-
try {
|
|
448
|
-
const response = await fetch(`${KRYPTOS_BASE_URL}/link-token`, {
|
|
449
|
-
method: "POST",
|
|
450
|
-
headers: {
|
|
451
|
-
"Content-Type": "application/json",
|
|
452
|
-
"X-Client-Id": YOUR_CLIENT_ID,
|
|
453
|
-
"X-Client-Secret": YOUR_CLIENT_SECRET,
|
|
454
|
-
},
|
|
455
|
-
body: JSON.stringify({
|
|
456
|
-
scopes:
|
|
457
|
-
"openid profile offline_access email portfolios:read transactions:read integrations:read tax:read accounting:read reports:read workspace:read users:read",
|
|
458
|
-
}),
|
|
459
|
-
});
|
|
460
|
-
|
|
461
|
-
const data = await response.json();
|
|
462
|
-
res.json({
|
|
463
|
-
link_token: data.link_token,
|
|
464
|
-
isAuthorized: false, // No access token provided
|
|
465
|
-
});
|
|
466
|
-
} catch (error) {
|
|
467
|
-
res.status(500).json({ error: "Failed to create link token" });
|
|
468
|
-
}
|
|
469
|
-
});
|
|
214
|
+
press → INTEGRATION → onConnectSuccess(null)
|
|
470
215
|
```
|
|
471
216
|
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
1. User taps "Connect to Kryptos"
|
|
475
|
-
2. Connect (INIT) screen initializes, then integration selection is shown
|
|
476
|
-
3. User selects and connects integrations
|
|
477
|
-
4. `onSuccess` receives `public_token` to exchange
|
|
478
|
-
|
|
479
|
-
#### Option B: With Access Token (Authenticated User)
|
|
217
|
+
---
|
|
480
218
|
|
|
481
|
-
|
|
219
|
+
## Backend endpoints
|
|
482
220
|
|
|
483
|
-
|
|
484
|
-
// Example: Node.js/Express
|
|
485
|
-
app.post("/api/kryptos/create-link-token", async (req, res) => {
|
|
486
|
-
try {
|
|
487
|
-
// Get the user's stored access token from your database
|
|
488
|
-
const userAccessToken = await getUserAccessToken(req.user.id);
|
|
221
|
+
### POST /link-token
|
|
489
222
|
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
"X-Client-Id": YOUR_CLIENT_ID,
|
|
495
|
-
"X-Client-Secret": YOUR_CLIENT_SECRET,
|
|
496
|
-
},
|
|
497
|
-
body: JSON.stringify({
|
|
498
|
-
scopes:
|
|
499
|
-
"openid profile offline_access integrations:read integrations:write",
|
|
500
|
-
access_token: userAccessToken, // Pass the user's access token
|
|
501
|
-
}),
|
|
502
|
-
});
|
|
503
|
-
|
|
504
|
-
const data = await response.json();
|
|
505
|
-
res.json({
|
|
506
|
-
link_token: data.link_token,
|
|
507
|
-
isAuthorized: true, // Access token provided, user is authenticated
|
|
508
|
-
});
|
|
509
|
-
} catch (error) {
|
|
510
|
-
res.status(500).json({ error: "Failed to create link token" });
|
|
511
|
-
}
|
|
512
|
-
});
|
|
223
|
+
```
|
|
224
|
+
Headers: X-Client-Id, X-Client-Secret
|
|
225
|
+
Body: { scopes, access_token? }
|
|
226
|
+
Returns: { data: { link_token } }
|
|
513
227
|
```
|
|
514
228
|
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
1. User taps "Connect to Kryptos"
|
|
518
|
-
2. Connect (INIT) then integration selection is shown
|
|
519
|
-
3. User selects integrations; `onSuccess` receives `null` (no new token needed)
|
|
520
|
-
|
|
521
|
-
#### Choosing the Right Approach
|
|
522
|
-
|
|
523
|
-
| Scenario | Use Option | isAuthorized | User Flow (mobile) | Returns public_token |
|
|
524
|
-
| ------------------------------------------ | ----------------- | ------------ | -------------------------------------------------------------------------- | -------------------- |
|
|
525
|
-
| First-time user connecting to Kryptos | A (Without Token) | `false` | INIT → Connect(account created for user on backend) → INTEGRATION → STATUS | ✅ Yes |
|
|
526
|
-
| User doesn't have an access token yet | A (Without Token) | `false` | INIT → Connect(account created for user on backend) → INTEGRATION → STATUS | ✅ Yes |
|
|
527
|
-
| Returning user with stored access token | B (With Token) | `true` | INIT → INTEGRATION → STATUS | ❌ No |
|
|
528
|
-
| Adding more integrations for existing user | B (With Token) | `true` | INIT → INTEGRATION → STATUS | ❌ No |
|
|
529
|
-
|
|
530
|
-
**Important notes:**
|
|
531
|
-
|
|
532
|
-
- After the first successful connection (Option A), store the `access_token` from the token exchange.
|
|
533
|
-
- Use the stored `access_token` for subsequent connections (Option B).
|
|
534
|
-
- For authorized users (`isAuthorized: true`), `onSuccess` receives `null`.
|
|
535
|
-
|
|
536
|
-
### 2. Exchange Public Token
|
|
537
|
-
|
|
538
|
-
After a successful connection, exchange the `public_token` for an `access_token`. **Important:** Store this `access_token` securely in your database. You will use it to create link tokens for authenticated users (Option B above).
|
|
539
|
-
|
|
540
|
-
```javascript
|
|
541
|
-
// Example: Node.js/Express
|
|
542
|
-
app.post("/api/kryptos/exchange-token", async (req, res) => {
|
|
543
|
-
try {
|
|
544
|
-
const { public_token } = req.body;
|
|
545
|
-
|
|
546
|
-
const response = await fetch(`${KRYPTOS_BASE_URL}/token/exchange`, {
|
|
547
|
-
method: "POST",
|
|
548
|
-
headers: {
|
|
549
|
-
"Content-Type": "application/json",
|
|
550
|
-
"X-Client-Id": YOUR_CLIENT_ID,
|
|
551
|
-
"X-Client-Secret": YOUR_CLIENT_SECRET,
|
|
552
|
-
},
|
|
553
|
-
body: JSON.stringify({
|
|
554
|
-
public_token,
|
|
555
|
-
}),
|
|
556
|
-
});
|
|
557
|
-
|
|
558
|
-
const data = await response.json();
|
|
559
|
-
|
|
560
|
-
// IMPORTANT: Store the access_token securely in your database
|
|
561
|
-
// You'll need this token to:
|
|
562
|
-
// 1. Create authenticated link tokens (Option B)
|
|
563
|
-
// 2. Make API calls on behalf of the user
|
|
564
|
-
await saveUserAccessToken(req.user.id, data.access_token);
|
|
229
|
+
### POST /token/exchange
|
|
565
230
|
|
|
566
|
-
res.json({ success: true });
|
|
567
|
-
} catch (error) {
|
|
568
|
-
res.status(500).json({ error: "Failed to exchange token" });
|
|
569
|
-
}
|
|
570
|
-
});
|
|
571
231
|
```
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
1. **First connection** (new user – `isAuthorized: false`):
|
|
576
|
-
|
|
577
|
-
```
|
|
578
|
-
App → generateLinkToken() [returns { link_token, isAuthorized: false }]
|
|
579
|
-
→ SDK: INIT → Connect → INTEGRATION → STATUS
|
|
580
|
-
→ User selects and connects integrations
|
|
581
|
-
→ onSuccess receives { public_token }
|
|
582
|
-
→ Backend exchanges public_token for access_token
|
|
583
|
-
→ Store access_token in database ← IMPORTANT
|
|
584
|
-
```
|
|
585
|
-
|
|
586
|
-
2. **Subsequent connections** (returning user – `isAuthorized: true`):
|
|
587
|
-
```
|
|
588
|
-
App → generateLinkToken() [returns { link_token, isAuthorized: true }]
|
|
589
|
-
→ SDK: INIT → INTEGRATION → STATUS
|
|
590
|
-
→ User sees integrations directly → connects more
|
|
591
|
-
→ onSuccess receives null
|
|
592
|
-
→ Integrations added to existing account
|
|
593
|
-
```
|
|
594
|
-
|
|
595
|
-
## Supported Platforms
|
|
596
|
-
|
|
597
|
-
- ✅ iOS 12.0+
|
|
598
|
-
- ✅ Android 5.0+ (API 21+)
|
|
599
|
-
- ✅ Expo SDK 48+
|
|
600
|
-
- ✅ React Native 0.60+
|
|
601
|
-
|
|
602
|
-
## Peer Dependencies
|
|
603
|
-
|
|
604
|
-
```json
|
|
605
|
-
{
|
|
606
|
-
"react": ">=16.8.0",
|
|
607
|
-
"react-native": ">=0.60.0",
|
|
608
|
-
"react-native-svg": ">=12.0.0"
|
|
609
|
-
}
|
|
232
|
+
Body: { public_token, client_id, client_secret }
|
|
233
|
+
Returns: { data: { access_token, token_type, expires_in } }
|
|
610
234
|
```
|
|
611
235
|
|
|
612
|
-
|
|
236
|
+
| Environment | Base URL |
|
|
237
|
+
| ----------- | -------------------------------- |
|
|
238
|
+
| Production | `https://connect-api.kryptos.io` |
|
|
613
239
|
|
|
614
|
-
|
|
615
|
-
- 📚 Documentation: [https://docs.kryptos.io](https://docs.kryptos.io)
|
|
616
|
-
- 💬 Discord: [Join our community](https://discord.gg/kryptos)
|
|
617
|
-
- 🐛 Issues: [GitHub Issues](https://github.com/kryptos/connect-npm-package/issues)
|
|
240
|
+
---
|
|
618
241
|
|
|
619
|
-
##
|
|
242
|
+
## Links
|
|
620
243
|
|
|
621
|
-
|
|
244
|
+
- [Kryptos Developer Portal](https://dashboard.kryptos.io/)
|
|
245
|
+
- [Full docs](https://docs.kryptos.io/)
|
|
622
246
|
|
|
623
|
-
|
|
247
|
+
## License
|
|
624
248
|
|
|
625
|
-
|
|
249
|
+
MIT © Kryptos
|