Privy’s security architecture leverages secure execution environments to protect your users’ assets. Wallet private keys are only temporarily reconstructed within these strictly isolated, secure execution environments when needed for sensitive operations.

Privy provides two types of secure execution environments: 1) via TEEs and 2) on the user’s device.

  • With TEE execution, wallets are reassembled within trusted execution environments (TEEs), also known as secure enclaves.
  • With on-device execution, wallets are reassembled directly on user devices.

Each environment ensures that private keys are never stored in complete form and are only temporarily reconstructed when needed.

Feature support

Your app must enable TEE execution in order to access the following features:

Unsupported features

Support for the following features is in active development for TEE-based execution:

  • Key import
  • Unity SDK
  • Farcaster signers

Migration guide

The following guide details how to migrate from on-device to TEE execution. When you enable TEE execution, all new wallets will be created within trusted execution environments (TEEs), and existing on-device wallets will be migrated to TEEs as users next visit your app. This is a one-way change.

Step 1: Identify your app’s execution environment

Navigate to the Privy Dashboard to verify your app’s wallet execution environment. On the Wallets page, navigate to the Advanced tab.

If your app is set to on-device execution, you will see the option to “Enable TEE execution”. If your app is already using TEE execution, you will not see this option. Apps may only enable one execution environment.

Step 2: Upgrade your SDKs

TEE execution is supported by the following SDK versions or later:

Client SDKs:

Server SDKs:

Step 3: Enable TEE execution in the Dashboard

In the Privy Dashboard, navigate to the Wallets page and then the Advanced tab. To enable TEE execution, select “Enable TEE execution” and confirm.

When you enable TEE execution, all new wallets will be created within trusted execution environments (TEEs). Existing user wallets will be migrated from on-device to TEEs via end-to-end encryption as users next visit your app.

Please note that:

  • Because the migration occurs automatically, all client-side features will be immediately available.
  • Only wallets that have been migrated to TEEs will support server-side features. Some users may not return to your app, so their wallets will remain on-device.
  • User-managed recovery (like cloud recovery) will no longer be prompted on new devices and will be disabled after migration.
  • This is a one-way change, and on-device execution is disabled once migration occurs.

Breaking changes

Enabling TEE-based execution involves a limited set of breaking changes. These breaking changes do not apply to most apps.

Unsupported features

A small number of features, such as key import, are not yet supported with TEE-based execution: list of unsupported features.

useSessionSigners

TEE execution enables deeper configurability for clients to provision server-side access to user wallets. In particular, the advanced interface enables your app to specify policies or multiple session signers on a wallet.

To provision server-side access to user wallets, use the useSessionSigner hook instead of the previous useDelegatedActions hook.

Adding session signers (previous)

import { useHeadlessDelegatedActions, ConnectedWallet } from '@privy-io/react-auth';

function SessionSignersButton(wallet: ConnectedWallet) {
  const { delegateWallet } = useHeadlessDelegatedActions();

  const handleAddSessionSigner = async () => {
    await delegateWallet({ address: wallet.address, chainType: wallet.type });
  }

  return (
    <div>
      <button onClick={() => handleAddSessionSigner()}>
        Add Session Signer
      </button>
    </div>
  );
}

Learn more about the previous interface here. The previous interface for revoking access can be found here.

Adding session signers (updated)

The updated interface allows a signer ID to be specified and for policies to be set which constrain that session signer.

import {useSessionSigners, ConnectedWallet} from '@privy-io/react-auth';

function SessionSignersButton(wallet: ConnectedWallet) {
  const {addSessionSigners} = useSessionSigners();

  const handleAddSessionSigner = async () => {
    await addSessionSigners({
      address: wallet.address,
      signers: [
          {
            signerId: "<insert-signer-id>",
            policyIds: ["<insert-policy-id"],
          },
        ],
    });
}

  return (
    <div>
      <button onClick={() => handleAddSessionSigner()}>
        Add Session Signer
      </button>
    </div>
  );
}

Learn more about the updated interface here. The updated interface for revoking access can be found here.

New advanced interfaces

Server-side wallet creation

TEE execution enables deeper configurability for server-side wallet creation. In particular, the advanced interface enables your app to specify policies and session signers when you create a wallet from your server.

The following interface update applies to importing a single user, batch importing users, and pregenerating wallets for existing users via the /users, /users/import and /users/[user_id]/wallets endpoints.

Wallet creation (previous)

create_ethereum_wallet
boolean

(Optional) Whether to create an Ethereum wallet for the user.

create_solana_wallet
boolean

(Optional) Whether to create a Solana wallet for the user.

create_ethereum_smart_wallet
boolean

(Optional) Whether to create an Ethereum smart wallet for the user.

number_of_ethereum_wallets_to_create
number

(Optional) The number of Ethereum wallets to pregenerate for the user. Defaults to 1.

Wallet creation (updated)

wallets
object[]
required

The wallets to create for the user.

Example usage

The following request body:

{
  "create_ethereum_wallet": true,
  "create_smart_wallet": true,
  "create_solana_wallet": true
}

can be updated to:

{
  "wallets": [{"chain_type": "ethereum", "create_smart_wallet": true}, {"chain_type": "solana"}]
}

In the updated interface, wallets may also set policies and session signers, e.g.:

{
  "wallets": [
    {"chain_type": "ethereum", "policy_ids": ["<policy-id>"], "create_smart_wallet": true},
    {
      "chain_type": "solana",
      "additional_signers": [
        {"signer_id": "<signer-id-1>", "override_policy_ids": ["policy-id-1"]},
        {"signer_id": "<signer-id-2>"}
      ]
    }
  ]
}