[Writer] Add Privy signer migration guides (React + JWT auth)#1230
[Writer] Add Privy signer migration guides (React + JWT auth)#1230JackReacher0807 wants to merge 8 commits intomainfrom
Conversation
🔗 Preview Mode
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 0fe1f72171
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
🔍 Link CheckStatus: ❌ Failed Summary
Broken links (85) — click to expandErrors per inputErrors in ./content/api-reference/katana/katana-api-overview.mdx
Errors in ./content/wallets/pages/smart-wallets/quickstart/index.mdx
Errors in ./content/wallets/pages/recipes/send-usdc.mdx
Errors in ./content/wallets/pages/recipes/smart-wallets-aave.mdx
Errors in ./content/wallets/pages/react-native/getting-started/getting-started-rn-bare.mdx
Errors in ./content/wallets/pages/index.mdx
Errors in ./content/changelog/2026-03-26.md
Errors in ./content/api-reference/op-mainnet/op-mainnet-api-faq/op-mainnet-api-faq.mdx
Errors in ./content/changelog/2026-04-09.md
Errors in ./content/wallets/pages/concepts/smart-account-client.mdx
Errors in ./content/wallets/wallet-integrations/privy/jwt-auth-migration.mdx
Errors in ./content/wallets/pages/authentication/overview.mdx
Errors in ./content/api-reference/arbitrum/arbitrum-api-faq/arbitrum-api-faq.mdx
Errors in ./content/tutorials/alchemy-university/smart-contract-basics/multi-sig-contracts.mdx
Errors in ./content/wallets/pages/react-native/getting-started/getting-started-expo.mdx
Errors in ./content/api-reference/hyperevm/hyperevm-api-overview.mdx
Errors in ./content/wallets/pages/bundler-api/bundler-faqs.mdx
Errors in ./content/api-reference/arbitrum-nova/arbitrum-nova-deprecation-notice.mdx
Errors in ./content/wallets/pages/recipes/onramp-funds.mdx
Errors in ./content/wallets/wallet-integrations/privy/react-migration.mdx
Errors in ./content/wallets/pages/recipes/upgrade-to-smart-accounts.mdx
Errors in ./content/wallets/pages/smart-wallets/how-to-stamp-requests.mdx
|
| // Add custom logic to only create a new embedded wallet | ||
| const walletCreationPluginOptions = { | ||
| shouldCreateWallet: ({user}: {user: User}) => | ||
| user.customMetadata?.['alchemy_org_id'] === undefined, |
There was a problem hiding this comment.
was this confirmed with danny? I remember they were looking to ship something that just did this automatically
There was a problem hiding this comment.
Good catch — went with the simpler path that matches the FAQ at the bottom: drop the custom wallet creation plugin entirely and set createOnLogin: "off" during the migration window, then flip it to "users-without-wallets" once everyone's migrated. That way we're not relying on the alchemy_org_id metadata check, and it's consistent whether or not Privy ships auto-detection down the road.
There was a problem hiding this comment.
@JackReacher0807 Revert this back to the original implementation. We do need the custom wallet creation plugin and should not pass the createOnLogin. Auto-detection was not shipped.
There was a problem hiding this comment.
Reverted in feee767. Step 1b is back to the original implementation: createWalletCreationOnLoginPlugin with shouldCreateWallet gated on alchemy_org_id, and createOnLogin: "users-without-wallets". Dropped the auto-detection / createOnLogin: "off" framing.
|
|
||
| ### 5a. Integrate Privy auth (server-side) | ||
|
|
||
| When selecting "Server side" in the Privy dashboard JWT configuration (Step 2a), Privy accepts JWTs directly from your backend. Your server exchanges the user's JWT for a Privy session via the REST API. |
There was a problem hiding this comment.
what's the reasoning behind recommending that? I thought it was to do it more securely (end to end encrypted), but it seems like this is just recommending they take 'custody' of the private key to migrate it themselves?
There was a problem hiding this comment.
Fair point — the original framing made it sound like server-side was the 'more secure' path, which isn't accurate since it does mean your server briefly holds the plaintext key. Reworked the section to be explicit: use the client-side path by default, only reach for server-side if you have a specific reason to do the import from the backend (e.g. attaching policies/owners at import time). Also replaced 'Server-side path' with 'Server-side path (import only)' in the heading so readers can't miss the scope.
| const user = await getUserFromDB(userId); | ||
|
|
||
| if (!user.signer_migrated) { | ||
| // 1. Export private key from Alchemy (Follow the steps from 4c) |
There was a problem hiding this comment.
step 4c is for the client. as far as I'm aware we have no customers authenticating a JWT signer on the backend and we do not support this
There was a problem hiding this comment.
This was the big one — thanks for catching it. Rewrote the whole server-side section to reflect that AlchemyWebSigner + JWT auth is browser-only and we don't support a backend Alchemy JWT signer auth. New flow: 1) client authenticates with Alchemy and calls exportPrivateKeyEncrypted against a public key your server owns, 2) client POSTs the ciphertext to your server, 3) server decrypts and calls privy.wallets().import(...). Added a at the top of the section making this explicit, and updated the 'Security considerations' section to match.
…options, clarify server-side JWT path - react-migration: drop cookieToInitialState references; switch to createOnLogin "off" during migration (removes custom wallet creation plugin) - react-migration: remove unnecessary 'Function, not hook' distinction and cookieToInitialState row from hook mapping - react-migration: move Info callout with deeper links below the bullet list - react-migration: passkey migration supports anonymous too - react-migration: use mode: 'redirect' (popup was never effective) - react-migration: load Alchemy API key from env var + add security Warning - react-migration: drop skipOrgVerification prop from the docs - react-migration: update FAQ to match simplified provider setup - jwt-auth-migration: explain new-user flow when createOnLogin is 'off' - jwt-auth-migration: fold redundant 4c 'Authenticate with Alchemy' into 4b; renumber subsequent steps - jwt-auth-migration: reframe server-side path as import-only (Alchemy JWT signer auth is client-only/unsupported on backend); show client export -> encrypted handoff -> server import
| |---|---| | ||
| | `useSignerStatus().isConnected` | `usePrivy().authenticated` | | ||
| | `useAuthModal().openAuthModal()` | `usePrivy().login()` | | ||
| | `useLogout()` | `usePrivy().logout` | |
There was a problem hiding this comment.
| | `useLogout()` | `usePrivy().logout` | | |
| | `useLogout()` | `usePrivy().logout()` | |
consistency
There was a problem hiding this comment.
Fixed: Added the parens — usePrivy().logout() now matches the other rows in the table. Commit: 3d7b2b2
| Wire Privy wallets to Alchemy's transaction infrastructure so gasless transactions, batching, and all your existing flows work again. This uses Alchemy SDK v5 with Wallet APIs. | ||
|
|
||
| * The client defaults to EIP-7702, which delegates the Privy wallet to a smart wallet at send time. | ||
| * If you were previously using ERC-4337 (with assets directly in smart accounts), see the EIP-7702 guide for non-7702 mode. You'll need to add an additional call to `wallet_requestAccount` before sending. |
There was a problem hiding this comment.
we should actually link to non-7702 guide here
There was a problem hiding this comment.
Fixed: Replaced the generic "EIP-7702 guide for non-7702 mode" link with a direct link to the non-7702 mode section: /wallets/transactions/using-eip-7702#how-to-use-non-7702-mode. Commit: 3d7b2b2
| ); | ||
| ``` | ||
|
|
||
| <Warning>Never commit your Alchemy API key to source control. Load it from an environment variable (for example `NEXT_PUBLIC_ALCHEMY_API_KEY` in Next.js) and restrict the key to the correct apps, networks, and origins from the [Alchemy Dashboard](https://dashboard.alchemy.com/).</Warning> |
There was a problem hiding this comment.
technically it's best for the api key to be secured on the backend
There was a problem hiding this comment.
Fixed: Strengthened the Warning — it now explicitly notes that for production apps the best practice is to keep the API key on the backend and proxy Alchemy requests through it rather than exposing it in the client bundle at all. Commit: 3d7b2b2
- Retitle React guide to clarify signer-only migration - Move Prerequisites to top of guide - Add React-only callout in intro - Condense Privy dashboard setup steps (remove redundant step, use current nav naming) - Fix usePrivy().logout() -> add parens for consistency - Link non-7702 mode guide directly (with anchor) - Note that chain can be any viem chain - Split migration SDK install so @account-kit/react/infra only install when not already present - Combine @account-kit/infra imports onto one line - Strengthen API key warning: recommend backend proxy for production - Polish Step 4 intro wording - Remove duplicate 'Redeploy app' step from cutover sequence - Use 'each wallet independently' instead of 'each chain independently' in FAQ - Link specific Privy JWT setup page in jwt-auth-migration.mdx
| transport: alchemyWalletTransport({ | ||
| apiKey: "YOUR_ALCHEMY_API_KEY", | ||
| }), | ||
| chain: arbitrumSepolia, |
There was a problem hiding this comment.
Clarify that you should import the needed chain(s) from viem/chains. ensure the chain is enabled on your Alchemy app and support gas sponsorship.
| // Add custom logic to only create a new embedded wallet | ||
| const walletCreationPluginOptions = { | ||
| shouldCreateWallet: ({user}: {user: User}) => | ||
| user.customMetadata?.['alchemy_org_id'] === undefined, |
There was a problem hiding this comment.
@JackReacher0807 Revert this back to the original implementation. We do need the custom wallet creation plugin and should not pass the createOnLogin. Auto-detection was not shipped.
| ### 3a. Install | ||
|
|
||
| ```bash | ||
| npm install @privy-io/alchemy-migration @account-kit/react @account-kit/infra |
There was a problem hiding this comment.
Remove the note to install @account-kit/react. We only need to install the migration pakage.
- Revert provider setup to original implementation: restore custom wallet creation plugin with createOnLogin set to 'users-without-wallets' (comment 3118799901). - Clarify Step 2c chain note: import chain(s) from viem/chains, ensure the chain is enabled on your Alchemy app, and confirm it supports Gas Manager sponsorship (comment 3118681754). - Remove the note about installing @account-kit/react and @account-kit/infra in Step 3a. The migration SDK is the only required install (comment 3118815590).
|
Thanks for the review, @avarobinson! Addressed all three in feee767 on
Ready for another pass when you have a minute. |
Adds 2 new documentation pages under the Wallets > Privy section for signer migration:
content/wallets/wallet-integrations/privy/react-migration.mdx): Step-by-step guide to migrate embedded wallets from Alchemy Account Kit to Privy using the React migration SDKcontent/wallets/wallet-integrations/privy/jwt-auth-migration.mdx): Guide for developers using JWT authentication, covering both client-side and server-side migration pathsBoth pages are added to the nav under a new 'Signer migration' group within the Privy section.
Linear: DOCS-42