Install
New features and improvements
- Unified provider + modal flows: Built-in UI for Passkey, Wallet, Email/SMS OTP, and OAuth (Google, Apple, Facebook, X, Discord).
- Automatic OAuth redirect handling: The provider completes OAuth redirects on page load; no manual token injection.
- First-class export/import: Secure export/import via Turnkey iframes with simple handlers.
- External wallet connection: Connect MetaMask, Phantom, WalletConnect providers for Ethereum/Solana.
- Session lifecycle management: Auto-refresh with
beforeSessionExpiry/onSessionExpiredcallbacks. - UI customization: Theme overrides, dark mode, border radius/background blur, and modal placement.
Breaking changes
Provider and hooks
Old Approach (Manual SDK) Previously,@turnkey/sdk-react exposed a TurnkeyProvider and a custom TurnkeyContext;
you manually managed multiple clients (passkeyClient, iframeClient, walletClient, indexedDbClient).
useTurnkey())
Use @turnkey/react-wallet-kit’s TurnkeyProvider and useTurnkey hook, which returns state (session, user, wallets, etc.),
high-level helpers (auth, export/import, signing, external wallets), and all TurnkeyClientMethods from @turnkey/core.
- Single provider + hook replaces multiple manually managed clients
- High-level helpers for auth/export/import/signing/external wallets
- All core client methods available via the hook
Configuration
Old Approach (Manual SDK iframe config) Previously, auth flows used iframe-specific configuration (e.g.,iframeUrl) and manual wiring for auth flows. OAuth often required redirect handling and token injection.
New Approach (Hook-Based Provider config)
Use the provider config with auth, ui, wallet configuration, and optional export/import iframe URLs. Built-in modal flows replace iframe-specific auth settings.
- Replace iframe-specific auth settings with
auth.*and built-in modal flows - Centralize OAuth settings via
auth.oauthConfig; redirect handling is automatic - Configure wallets/chains and UI theming directly on the provider
Authentication
- Manual client selection/injection has been replaced by a single modal-driven flow (
handleLogin) and dedicated OAuth helpers. Stop callinginjectCredentialBundleon iframes; the provider manages sessions and completes OAuth automatically.
OAuth
Old Approach (Manual SDK) Previously, you manually parsedcode/state from the URL, exchanged for a token, and injected credentials into an iframe.
New Approach (Hook-Based: useTurnkey())
Use a dedicated helper to trigger the OAuth flow. The provider completes redirects automatically on load.
- No manual URL parsing/token exchange/injection
- Single helper per provider; popup or full-page redirect
- Redirect completion handled automatically by the provider
Passkeys
Old Approach (Manual SDK) Previously, passkey login used a read/write session with a freshly generated public key. Passkey signup first created a WebAuthn credential (challenge + attestation) and then created a new sub-organization/user using that credential.useTurnkey())
Use the built-in helpers to trigger passkey login and sign-up flows.
- No manual public key management or session type selection
- WebAuthn challenge/attestation handled by helpers and proxy
- Provider manages session creation and storage
OTP (SMS & Email)
Old Approach (Manual SDK + Server Actions) Previously, OTP auth required:- A server action to initialize OTP (and optionally create a sub-org if none exists) using the parent org API key.
- A server action to verify OTP and exchange the verification token for a session (read/write), stamped by the server key.
- Client code to fetch the device public key and then call those server actions.
useTurnkey())
The provider handles proxy calls; you no longer need to stamp server-side with the parent org key, nor manually exchange verification tokens. Client code initializes OTP and completes it with completeOtp.
Initialize (client):
- Server-stamped flows (parent org API key) are no longer required for standard OTP; the provider’s proxy methods handle the secure exchange.
- You call
proxyInitOtpandcompleteOtpdirectly from the client; the SDK manages session creation and storage. - Optional sub-org creation can be passed via
createSubOrgParamsduring completion.
Wallet Authentication (Ethereum/Solana)
Old Approach (Manual SDK + Server Actions) Previously, wallet authentication required:- Configuring Turnkey with a Wallet interface (e.g.,
EthereumWallet) and wrapping your app with the provider. - Deriving a public key from the user’s external wallet (for Ethereum this involves a signMessage prompt).
- Optionally creating a sub-organization (sign-up) on the server using the parent org API key pair.
- Creating a read/write session via
loginWithWallet, bound to a browser-managed IndexedDB API key.
useTurnkey())
Use the hook-based helpers to trigger wallet authentication flows. The provider abstracts provider discovery, public key derivation, and session creation/storage. A single call will prompt the external wallet for any required signatures and establish a Turnkey session.
Key differences:
- No manual
walletClient.getPublicKey()or message signing to derive a public key - No
SessionTypeor manual IndexedDB session management; the provider manages session lifecycle - One-liners for “Continue with Wallet” (auto sign in or sign up), or explicit Sign Up / Sign In
- Works for Ethereum and Solana; pass
Chain.EthereumorChain.SolanatogetWalletProvidersand choose a provider
Passkeys
Add passkey
Before:Remove passkey
Before:Wallets
List wallets
Old Approach (Manual SDK Calls) Previously, wallet listing relied on manually instantiating a Turnkey client and invoking SDK methods to fetch both wallets and their accounts.useTurnkey())
The new method utilizes the useTurnkey React hook, which abstracts data fetching, session management, and provides ready-to-use wallet/account lists and actions.
- No manual wallet/account fetch + merge
- Hook provides wallets and accounts with provider-managed session
- Simpler state consumption via
useTurnkey()
Creating Wallets and Accounts
Old Approach (Manual SDK Calls) Previously, creating wallets and accounts involved calling SDK methods directly (e.g.,createWallet, createWalletAccounts) and then refetching wallets to reflect changes.
Additionally, when creating a new Ethereum account you would often compute the next default account at a specific index via a helper (e.g., defaultEthereumAccountAtIndex(index)) and pass that into createWalletAccounts.
useTurnkey())
Use useTurnkey() helpers createWallet and createWalletAccounts.
The provider manages session and state and refreshing wallets; you only invoke the actions.
Export
Old Approach (Manual SDK + iframe) Previously, exporting required manually initializing an export iframe and orchestrating export API calls and decryption within the iframe.useTurnkey())
Use the built-in export handlers that open a modal and perform the export/iframe flow for you.
- Modal handlers replace manual iframe client orchestration
- No direct bundle injection/extraction steps
- Provider/session context handled automatically
Import
Old Approach (Manual SDK + iframe)useTurnkey())
Signing
Transactions
Old Approach Previously, transactions were signed usingethers with TurnkeySigner from @turnkey/ethers, wired to the @turnkey/sdk-react client.
You manually constructed the signer/provider and invoked sendTransaction.
useTurnkey()’s signing helpers:
signTransaction: signs and returns a signature (you broadcast separately).signAndSendTransaction: signs and broadcasts, returning the on-chain transaction hash.
rpcUrl is required when using embedded wallets (to broadcast via your chosen RPC).
For external wallets (e.g., MetaMask, Phantom), rpcUrl is not required and will be ignored.
Key differences:
- No
TurnkeySigneror manual provider wiring - Pass an unsigned transaction and account; SDK stamps and sends
- Session/state handled by the provider
Messages
Old Approach Messages were signed viaethers using TurnkeySigner from @turnkey/ethers, with manual signer/provider wiring against the @turnkey/sdk-react client.
useTurnkey()’s signMessage to sign directly with a selected wallet account. For a modal-driven UX, handleSignMessage opens a confirmation dialog.