Skip to main content

The biggest change: no more credential bundles

With @turnkey/sdk-react-native, authentication ended with a credential bundle: your app created an embedded key with createEmbeddedKey, your backend ran an auth activity such as OTP_AUTH with that key as the target, and the app decrypted the result with createSession({ bundle }). @turnkey/react-native-wallet-kit has no bundles. The app generates its own key pair, which never leaves the device. Authentication is bound to that key, and login returns a session JWT for it. The kit stores the session and refreshes it for you. This changes your authentication code on both the app and, if you have one, your backend. It is more than a package rename.
Sessions are stored differently, so existing sessions are not carried over. Users sign in again after you upgrade.

Install

The kit also needs a few native modules and a polyfill. See Getting started for the full install, platform setup, and the deep link scheme that OAuth needs. For a working reference, see the with-react-native-wallet-kit example app.

New features and improvements

  • Auth helpers for every method: email and SMS OTP, passkeys, OAuth (Google, Apple, Facebook, X, Discord), and WalletConnect wallets.
  • Optional backend: use Turnkey’s Auth Proxy for signup and login without running your own backend, or keep your backend.
  • Session lifecycle management: sessions are stored and refreshed automatically, with beforeSessionExpiry and onSessionExpired callbacks.
  • Managed state: user, wallets, session, and authState are kept up to date by the provider.
  • Signing helpers: sign messages and transactions, or sign and broadcast, with a wallet account.
The kit has no built-in UI. You build your own screens and call the hook’s functions.

Breaking changes

Provider and hooks

Old approach
New approach
Key differences:
  • Configuration goes in config and lifecycle hooks in callbacks.
  • onSessionCreated, onSessionSelected, onSessionCleared, onSessionEmpty, and onInitialized have no direct equivalent. Use onAuthenticationSuccess, or read authState and clientState from the hook.
  • client is replaced by httpClient. See Other API calls.

Configuration

When you set authProxyConfigId, OTP, OAuth client IDs, and session settings come from the Auth Proxy configuration in the Turnkey dashboard. See Getting started for every option.

Sessions

Authentication

Email and SMS OTP

Old approach The app created an embedded key, your backend initialized OTP and then ran OTP_AUTH with the embedded key as the target, and the app decrypted the returned credential bundle.
New approach, with the Auth Proxy The kit handles the whole exchange. Initialize OTP, then complete it with the code. completeOtp signs the user up if they do not have a sub-organization yet.
New approach, with your own backend If your backend runs OTP with @turnkey/sdk-server, the flow changes on both sides. The code is encrypted on the device, so your backend never sees it, and login is bound to the app’s key pair through a client signature.
  1. The app calls createApiKeyPair().
  2. Your backend calls initOtp (INIT_OTP_V3). appName is required. It returns otpId and otpEncryptionTargetBundle.
  3. The app encrypts the code with encryptOtpCodeToBundle from @turnkey/crypto.
  4. Your backend calls verifyOtp (VERIFY_OTP_V2) with the encrypted bundle. It returns a verificationToken.
  5. Your backend looks up or creates the user’s sub-organization, as before.
  6. The app builds the login message with getClientSignatureMessageForLogin and signs it with signWithApiKey.
  7. Your backend calls otpLogin (OTP_LOGIN_V2) on the sub-organization. It returns the session JWT.
  8. The app calls storeSession.
getClientSignatureMessageForLogin is not re-exported by @turnkey/react-native-wallet-kit. Install @turnkey/core and import it from there.
The otp-auth/with-backend example implements this flow with @turnkey/react-wallet-kit. The backend is identical for React Native, and the app side differs only in the @turnkey/core import above. Other changes to the OTP flow:
  • OTP_AUTH returned an API key ID and a credential bundle. Neither exists in the new flow.
  • Email customization moves to the emailCustomization parameter of INIT_OTP_V3.
  • See the OTP migration guide for the activity changes in detail.

Passkeys

Old approach @turnkey/sdk-react-native exported createPasskey and PasskeyStamper, and you wired signup and login to your backend yourself. New approach
See Passkey authentication for the rpId and associated domains setup.

OAuth

Old approach handleGoogleOAuth returned an OIDC token through onSuccess, and your backend used it to sign the user up or log them in.
New approach Each provider has a helper that opens the browser, handles the deep link back to your app, and completes signup or login.
The helpers need auth.oauth.appScheme and the provider client IDs in your config. Pass onOauthSuccess if you want to receive the OIDC token and complete authentication yourself. See Social logins.

Wallet authentication

This is new. Users can sign in with an external wallet through WalletConnect, using loginOrSignupWithWallet. It requires walletConfig with a WalletConnect project ID; see the example app for the configuration.

Passkey management

Adding and removing passkeys is new:

Wallets

List wallets

Old approach Wallets were nested under user.wallets.
New approach Wallets are top-level state, kept up to date by the provider. user is now a v1User, with fields such as userId, userName, and userEmail.

Create wallets and accounts

createWallet now returns the wallet ID instead of an activity, and createWalletAccounts is new.

Export and import

There is no export iframe on React Native. exportWallet decrypts the export on the device and returns the mnemonic to your app, as before, so your app decides how to display it.
exportWalletAccount, exportPrivateKey, and importPrivateKey are also available. See Importing and exporting wallets.

Signing

Old approach
New approach Signing takes a wallet account from wallets, not an address string.
signAndSendTransaction signs and broadcasts in one step. See Signing.

Other API calls

For any API call without a helper, use httpClient instead of the old client. It stamps requests with the current session, and takes the activity parameters directly instead of the full request envelope. Old approach
New approach
See Advanced API requests.

Errors

The kit throws TurnkeyError with a code from TurnkeyErrorCodes, such as INVALID_OTP_CODE or MAX_OTP_INITIATED_ERROR, instead of raw API errors. Import both from @turnkey/sdk-types. You can also handle every error in one place with the onError callback on TurnkeyProvider.