If you use standard auth methods (email, Google, and passkeys) with the React SDK, use the React
migration guide instead.
Before starting, read the signer migration
overview
to confirm your account type (Modular Account v2 vs. another implementation) and connection type
(EIP-7702 vs. ERC-4337). Apps not on MAv2, or using pure 4337, need to adjust a step in this guide
— the overview’s Edge
cases
section walks through each.
How JWT migration differs from standard migration
With JWT auth, you control both sides of authentication — your server generates JWTs, and both Alchemy and your new provider accept them. This simplifies the migration because:- No user export/import needed (unless you also use other auth methods) — both providers authenticate via your JWT
- JWTs are reusable — they’re not one-time-use tokens, so the same JWT can authenticate with both Alchemy and Privy in a single session
- Migration detection is your responsibility — since there’s no Privy-side metadata, you track which users have migrated in your own database
Choose your integration path
This guide covers two paths. Both share the same Privy dashboard setup (Steps 1–2a), but differ in how authentication and wallet import happen:Step 1: Add a migration tracking field to your user database
Add a field to your user/account model to track migration status. Every existing user starts asneeds_migration = true.
Step 2: Set up Privy with JWT auth
2a. Create a Privy app and configure JWT verification
This setup is the same regardless of whether you choose the client-side or server-side path.- Go to the Privy Dashboard and create an app
- Request access to Custom Auth Support in the Integrations > Plugins tab
- Navigate to User Management > Authentication > JWT-based auth
- Select the environment:
- Client side if JWT-authenticated requests will come from end-user devices (React / React Native)
- Server side if requests will come from your backend servers
- Provide your JWT verification key — either a JWKS endpoint URL or a public verification key (PEM certificate)
- Enter the JWT claim that contains the user’s unique ID (usually
sub)
2b. Disable automatic wallet creation during migration
While existing users still need migrating, you don’t want Privy to auto-create a fresh wallet before you import their Alchemy wallet. If using a client SDK, setcreateOnLogin: "off":
signer_migrated = true (no Alchemy wallet to migrate). Create a Privy wallet for them explicitly after login — either by calling createWallet from the client SDK or via the @privy-io/node SDK server-side. Once all existing users have migrated, switch createOnLogin back to "users-without-wallets" and you can drop the explicit creation call.
Step 3: Reconnect sending and gas sponsorship
Install@alchemy/wallet-apis and wire up createSmartWalletClient. See the Privy signer integration guide for full setup details, or follow the React migration guide Step 2 for a walkthrough.
Client-side path
Use this path if you have a React or React Native app and want the migration to happen in the user’s browser/device.4a. Integrate Privy auth (client-side)
Instead of calling a Privy login function directly, you subscribe the Privy SDK to your existing auth provider’s state using theuseSubscribeToJwtAuthWithFlag hook. Privy will automatically authenticate when your provider reports the user is logged in.
In a component that lives below both PrivyProvider and your auth provider:
usePrivy:
4b. Build the client-side migration flow
The migration happens in a single session where the user is authenticated with both Alchemy and Privy simultaneously.4c. Export details
The snippet in 4b already authenticates with Alchemy using the same JWT and callsexportPrivateKey(). A note on when to use the encrypted variant:
4d. Import into Privy (client-side)
Use theuseImportWallet hook from @privy-io/react-auth. It accepts a raw hex private key (with or without 0x prefix) for Ethereum, or a base58-encoded key for Solana.
Ethereum:
4e. Mark migration complete
Update your database so the user isn’t prompted again on next login.Server-side path (import only)
5a. Set up the Privy Node SDK
In the Privy dashboard JWT configuration (Step 2a), select “Server side” so Privy will accept JWTs from your backend. Then install the SDK:5b. Ship the exported key to your server
On the client, export the private key from Alchemy as in 4c. To avoid sending plaintext key material over the network, useexportPrivateKeyEncrypted with a public key owned by your backend:
5c. Import into Privy from your backend
Decrypt the key with your server’s private key, then pass it to the Node SDK.@privy-io/node re-encrypts the key with HPKE before sending it to Privy’s TEE, so the plaintext key never leaves your server over the wire.
5c. Import into Privy (server-side)
The@privy-io/node SDK encrypts the key material automatically for secure transmission to the TEE.
Ethereum (raw private key):
REST API alternative
If you’re not using Node.js, use the REST API directly. The flow is three steps:- Initialize — call
/v1/wallets/import/initto get an encryption public key:
-
Encrypt — encrypt the private key using HPKE with the returned public key (KEM:
DHKEM_P256_HKDF_SHA256, KDF:HKDF_SHA256, AEAD:CHACHA20_POLY1305). -
Submit — call
/v1/wallets/import/submitwith the encrypted key:
5d. Mark migration complete
Step 6: Deploy
Unlike the React migration, JWT migration does not require a user export/import step — unless your users also use other auth methods (email, Google, etc.) alongside JWT. If JWT is your only auth method:- Deploy your updated app
- Users authenticate via JWT with Privy going forward
- Migration happens automatically on each user’s first login
- No Alchemy dashboard export needed
- You still need to export users from Alchemy and import into Privy (see React migration guide Step 4)
- Follow the same Deploy → Export → Import sequence
Next steps
After migration, follow the Privy guides for using embedded wallets:- Send a transaction (generic wallet usage)
- Create authorization keys (for server-side usage of wallets)
- Prepare smart wallet operations
- Sign smart wallet operations
Important notes
No user export/import needed (JWT-only)
Because JWT authentication is controlled by your server, both Alchemy and Privy can verify the same JWT. There’s no user metadata to transfer — your server is the source of truth for user identity. The only thing being migrated is the private key material.Security considerations
- Client-side path: The private key is briefly available in client memory during the export→import handoff. This is different from the React SDK which uses encrypted TEE-to-TEE transfer.
- Server-side path: The key leaves the client encrypted against your server’s public key, is decrypted briefly on your server, then re-encrypted with HPKE by
@privy-io/nodebefore being sent to Privy’s TEE. The plaintext is only briefly available on your server, never over the wire.

