How to get both EVM and Solana wallets from Web3Auth JWT on server-side?

I’m trying to get BOTH EVM and Solana wallet on server-side after user has done .login({ loginProvider: LOGIN_PROVIDER.JWT }).

But I only get the EVM key!

const { payload } = await jose.jwtVerify(…)
// payload.wallets only has secp256k1 wallets

===

When I do web3Auth.login({ curve:’ed25519’ }) I assume I would get Solana address in JWK? But I need both addresses!

===

How would I get, from the Web3Auth JWT, both of the wallet addresses at the same time? Is there maybe a switch I can flip somewhere in the dashboard (I tried to look for it)?

Thanks — I see you’re reporting an issue (server-side) trying to get both EVM and Solana wallets from a single Web3Auth JWT after .login(). I’ll summarize what you gave, list what I need, explain why this happens, and show recommended approaches.

Extracted info for the support team

  • SDK Details: MetaMask Embedded Wallets (Web3Auth)
  • SDK Version Number: (not provided — please share)
  • Platform: (not provided — web / node / mobile? please share)
  • User-provided behavior: After verifying JWT (jose.jwtVerify) payload.wallets only contains secp256k1 wallets. You tried web3Auth.login({ curve: ‘ed25519’ }) but need both addresses at once.

Why this happens

  • Web3Auth’s JWT includes wallet entries for the curve you requested at login. If you login with curve: ‘secp256k1’ you get EVM-compatible keys; with curve: ‘ed25519’ you get Solana-compatible keys.
  • There is no current option or dashboard switch to include both secp256k1 and ed25519 keypairs in a single JWT. You cannot natively obtain both keypairs in a single login/JWT.

Recommended approaches

  1. Two logins (most straightforward)
  • Client: perform two logins (one per curve) and send both idTokens/JWTs to your server.
    • Example client flow (conceptual):
      • const evmJWT = await web3Auth.login({ curve: ‘secp256k1’ })
      • const solJWT = await web3Auth.login({ curve: ‘ed25519’ })
      • POST { evmJWT, solJWT } to your server
  • Server: verify each JWT separately and read payload.wallets for each.
    • Example server (node + jose, conceptual):
      • const evmPayload = await jose.jwtVerify(evmJWT, jwkOrKey)
      • const solPayload = await jose.jwtVerify(solJWT, jwkOrKey)
      • const evmWallets = evmPayload.payload.wallets
      • const solWallets = solPayload.payload.wallets
  1. Export both keys from the client session (if available)
  • If your client-side Web3Auth session or provider exposes both keypairs (or can derive both) you can export the public addresses for both chains and send only the addresses or verified tokens to your server. This avoids multiple login prompts if supported by your client flow.
  1. Don’t send raw private keys to the server
  • For security, avoid sending private keys or storing them server-side. Use JWTs or signed attestations instead.

Notes and cautions

  • Deriving an ed25519 key from a secp256k1 private key (or vice versa) is not feasible/safe — do not attempt this.
  • If you need a single-server-side assertion that ties both addresses to the same user, you can have the client sign a challenge with each wallet and send both signatures plus the JWT(s) to the server.

Relevant docs

What I need from you to continue troubleshooting

  • SDK version you’re using and the platform (web / node / mobile)
  • The client init + login code snippet you’re using (so I can confirm login options)
  • Optional: the decoded JWT payload (or a sanitized screenshot of payload.wallets) or browser console logs if you’ve already verified the JWT and are still seeing unexpected results

If you want, paste your login/init snippet and SDK version and I’ll point out exact code changes you should make to implement the two-login or export flow.

Note: This response was generated by an AI bot and may require further verification. The MetaMask Community Team has tracked this issue and will be responding as soon as possible.

Additionally, we would recommend you to join our biweekly Office Hours to get this resolved even faster. MetaMask Developer Office Hours

This is now solved. The issue was I had the default RPC URL in under Solana in Web3Auth dashboard. If I changed it to be a proper paid RPC endpoint, it succeeds. Probably web3auth cannot (IP is banned from?) using the default solana RPC. Anyway, now it is OK and I get the solana in the JWT payload!

1 Like

Hi @silver, thank you for the update.