Skip to content

Commit 7a7e66e

Browse files
committed
Merge pull-request #520
adds support for multiple sessions by allowing sessions to be created with a custom sessionKey instead of using a single default session
2 parents 8c89cbd + fcf9503 commit 7a7e66e

11 files changed

+1035
-577
lines changed

.changeset/healthy-teachers-battle.md

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
---
2+
"@turnkey/sdk-react-native": major
3+
---
4+
5+
This breaking change adds support for multiple sessions:
6+
7+
- The concept of a **selected session** has been introduced:
8+
- Users can switch between sessions using `setSelectedSession({ sessionKey: <key> })`.
9+
- The selected session determines the active `client`, `user`, and `session` state.
10+
- API calls such as `updateUser`, `createWallet`, and `signRawPayload` now apply to the selected session.
11+
- A session limit of **15 active sessions** has been enforced:
12+
- If the limit is reached, users must remove an existing session before creating a new one.
13+
- Expired or invalid sessions are automatically cleaned up.

packages/sdk-react-native/README.md

+56-55
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
The `@turnkey/sdk-react-native` package simplifies the integration of the Turnkey API into React Native applications. It provides secure session management, authentication, and cryptographic operations using [`react-native-keychain`](https://github.com/oblador/react-native-keychain), [`@turnkey/crypto`](../crypto/), [`@turnkey/api-key-stamper`](../api-key-stamper/), and [`@turnkey/http`](../http/).
66

7+
---
8+
79
## **Installation**
810

911
- Install the following dependencies in your React Native project:
@@ -35,17 +37,20 @@ export const AppProviders = ({ children }: { children: React.ReactNode }) => {
3537

3638
const turnkeyConfig = {
3739
apiBaseUrl: "https://api.turnkey.com",
38-
organizationId: <"your organization id">
39-
onSessionCreated: () => {
40-
console.log("Session Created");
40+
organizationId: "<your organization id>",
41+
onSessionCreated: (session) => {
42+
console.log("Session Created", session);
43+
},
44+
onSessionSelected: (session) => {
45+
console.log("Session Selected", session);
4146
router.replace("/dashboard");
4247
},
43-
onSessionExpired: () => {
44-
console.log("Session Expired");
48+
onSessionExpired: (session) => {
49+
console.log("Session Expired", session);
4550
router.push("/");
4651
},
47-
onSessionCleared: () => {
48-
console.log("Session Cleared");
52+
onSessionCleared: (session) => {
53+
console.log("Session Cleared", session);
4954
router.push("/");
5055
},
5156
};
@@ -56,78 +61,74 @@ export const AppProviders = ({ children }: { children: React.ReactNode }) => {
5661

5762
---
5863

64+
## **Session Storage**
65+
66+
To enable secure authentication, the following storage keys are used:
67+
68+
- `@turnkey/embedded-key`: Stores the private key that corresponds to the public key used when initiating the session request to Turnkey.
69+
- `@turnkey/session`: Default session storage key, storing the session credentials, including the private key, public key, and expiry time, which are decrypted from the credential bundle after a session is created.
70+
- `@turnkey/session-keys`: Stores the list of stored session keys.
71+
- `@turnkey/selected-session`: Stores the currently selected session key.
72+
73+
---
74+
5975
## **Functions Provided by the Turnkey Provider**
6076

6177
### **Session Management**
6278

6379
- `createEmbeddedKey()`: Generates a new embedded key pair and securely stores the private key.
64-
- `createSession(bundle, expiry?)`: Creates a session from a given credential bundle with an optional expiry time.
65-
- `clearSession()`: Clears the current session, removing all stored credentials and session data.
80+
- `createSession({ bundle, expirationSeconds?, sessionKey? })`: Creates a session. [(API Docs)](https://docs.turnkey.com/api#tag/Sessions/operation/CreateReadWriteSession)
81+
- If `sessionKey` is provided, the session will be stored under that key in secure storage.
82+
- If no session exists, the first session created is **automatically selected**.
83+
- If a session with the same `sessionKey` already exists in secure storage, an error is thrown.
84+
- `setSelectedSession({ sessionKey })`: Selects a session by its key (Used when handling multiple sessions).
85+
- `clearSession({ sessionKey? })`: Removes the specified session from secure storage. If no `sessionKey` is provided, the currently selected session is removed.
86+
- `clearAllSessions()`: Clears all sessions from secure storage.
87+
88+
---
6689

6790
### **User Management**
6891

69-
- `updateUser()`: Updates the user's email and/or phone number.
70-
- `refreshUser()`: Fetches the latest user data and updates the session state.
92+
- `updateUser({ email?, phone? })`: Updates the user's email and/or phone number. [(API Docs)](https://docs.turnkey.com/api#tag/Users/operation/UpdateUser)
93+
- `refreshUser()`: Fetches the latest user data. [(API Docs)](https://docs.turnkey.com/api#tag/Sessions)
94+
95+
---
7196

7297
### **Wallet Management**
7398

74-
- `createWallet()`: Creates a new wallet with the specified name and accounts. Optionally, a mnemonic length can be provided (defaults to 12).
75-
- `importWallet()`: Imports a wallet using a provided mnemonic and creates accounts.
76-
- `exportWallet()`: Exports an existing wallet by decrypting the stored mnemonic phrase.
99+
- `createWallet({ walletName, accounts, mnemonicLength? })`: Creates a wallet. [(API Docs)](https://docs.turnkey.com/api#tag/Wallets/operation/CreateWallet)
100+
- `importWallet({ walletName, mnemonic, accounts })`: Imports a wallet. [(API Docs)](https://docs.turnkey.com/api#tag/Wallets/operation/ImportWallet)
101+
- `exportWallet({ walletId })`: Exports a wallet mnemonic. [(API Docs)](https://docs.turnkey.com/api#tag/Wallets/operation/ExportWallet)
77102

78103
### **Transaction Signing**
79104

80-
- `signRawPayload()`: Signs a raw payload using the specified signing key and encoding parameters.
105+
- `signRawPayload({ signWith, payload, encoding, hashFunction })`: Signs a payload. [(API Docs)](https://docs.turnkey.com/api#tag/Signing/operation/SignRawPayload)
81106

82107
---
83108

84-
### **Creating a new Session**
109+
## **Handling Multiple Sessions**
85110

86-
```tsx
87-
import { useTurnkey } from "@turnkey/sdk-react-native";
88-
import { PasskeyStamper } from "@turnkey/react-native-passkey-stamper";
89-
import { TurnkeyClient } from "@turnkey/http";
90-
91-
const { createEmbeddedKey, createSession } = useTurnkey();
92-
93-
const loginWithPasskey = async () => {
94-
try {
95-
const stamper = new PasskeyStamper({ rpId: RP_ID });
96-
const httpClient = new TurnkeyClient({ baseUrl: TURNKEY_API_URL }, stamper);
97-
98-
const targetPublicKey = await createEmbeddedKey();
99-
100-
const sessionResponse = await httpClient.createReadWriteSession({
101-
type: "ACTIVITY_TYPE_CREATE_READ_WRITE_SESSION_V2",
102-
timestampMs: Date.now().toString(),
103-
organizationId: TURNKEY_PARENT_ORG_ID,
104-
parameters: { targetPublicKey },
105-
});
106-
107-
const credentialBundle =
108-
sessionResponse.activity.result.createReadWriteSessionResultV2
109-
?.credentialBundle;
110-
111-
if (credentialBundle) {
112-
await createSession(credentialBundle);
113-
}
114-
} catch (error) {
115-
console.error("Error during passkey login:", error);
116-
}
117-
};
118-
```
111+
Most users won't need multiple sessions, but if your app requires switching between multiple sessions, here’s what you need to know:
119112

120-
---
113+
This SDK supports **multiple sessions**, allowing you to create and switch between different session keys using `setSelectedSession({ sessionKey })`. When a session is selected, the client, user, and session information are updated accordingly, so that all subsequent function calls (like `updateUser` or `createWallet`) apply to the selected session.
121114

122-
### **Session Storage**
115+
- **Creating a Session with a Custom Id**: You can pass a `sessionKey` when calling `createSession`. If provided, the session will be stored in secure storage under that ID, allowing for multiple sessions.
116+
- **Switching Sessions**: Use `setSelectedSession({ sessionKey })` to switch between stored sessions. The client, user, and session information will automatically update.
117+
- **Session Expiry Management**: Each session has an expiry time, and expired sessions will be automatically cleared.
118+
- **Callbacks for Session Events**:
119+
- `onSessionCreated`: Called when a session is created.
120+
- `onSessionSelected`: Called when a session is selected.
121+
- `onSessionExpired`: Called when a session expires.
122+
- `onSessionCleared`: Called when a session is cleared.
123123

124-
To enable secure authentication, two separate keychain entries are used:
124+
**When are multiple sessions useful?**
125125

126-
- `turnkey-embedded-key`: Stores the private key that corresponds to the public key used when initiating the session request to Turnkey.
127-
- `turnkey-session`: Stores the session credentials, including the private key, public key, and expiry time, which are decrypted from the credential bundle after a session is created.
126+
Using multiple sessions can be beneficial when enabling different authentication methods for various operations. For example, you might authenticate a user with OTP for login while using a passkey-based session for signing transactions.
128127

129128
---
130129

131130
## **Demo App**
132131

133-
Check out [this repository](https://github.com/tkhq/react-native-demo-wallet) for a full working example of session management in React Native.
132+
Check out [this repository](https://github.com/tkhq/react-native-demo-wallet) for a full working example.
133+
134+
---

packages/sdk-react-native/package.json

+5-6
Original file line numberDiff line numberDiff line change
@@ -50,12 +50,11 @@
5050
"@turnkey/api-key-stamper": "workspace:*",
5151
"@turnkey/crypto": "workspace:*",
5252
"@turnkey/encoding": "workspace:*",
53-
"@turnkey/http": "workspace:*",
54-
"react": "18.3.1",
55-
"react-native": "^0.76.5",
56-
"react-native-keychain": "^8.1.0"
53+
"@turnkey/http": "workspace:*"
5754
},
58-
"devDependencies": {
59-
"@types/react": "^18.2.6"
55+
"peerDependencies": {
56+
"@types/react": "^18.2.75",
57+
"react": "^16.8.0 || ^17.0.0 || ^18.0.0",
58+
"react-native-keychain": "^8.1.0 || ^9.2.2"
6059
}
6160
}

packages/sdk-react-native/src/constant.ts

-4
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
export enum StorageKeys {
2+
DefaultSession = "@turnkey/session",
3+
EmbeddedKey = "@turnkey/embedded-key",
4+
SessionKeys = "@turnkey/session-keys",
5+
SelectedSession = "@turnkey/selected-session",
6+
}
7+
8+
export const OTP_AUTH_DEFAULT_EXPIRATION_SECONDS = 15 * 60;
9+
export const MAX_SESSIONS = 15;

0 commit comments

Comments
 (0)