Eject a wallet
Eject combines a user’s two matching MPC backup shares into a raw private key, letting them move a wallet off MPC and, on EVM chains, import it into a wallet manager like MetaMask.Warning: Providing the custodian backup share to the client device puts both MPC shares on a single device, removing the multi-party security benefits of MPC. This operation should only be done for users who want to move off of MPC and into a single private key.
Ejecting a Wallet
To eject the private keys for your wallets, the two matching backup shares need to be combined. This is done by fetching the backup shares and then combining them with the @portal-hq/eject-js NPM package.@portal-hq/eject-js combines two plaintext MPC shares into a raw private key. It does not fetch or decrypt shares for you - your code is responsible for retrieving each share and, when using Portal-Managed Backups, decrypting the client backup share before passing it in.
Share encodings differ. The client backup share you get from Store the client share encrypted at rest, as Back up a wallet describes. Once you decrypt it, its base64 form is what
/v1/backup is base64-encoded JSON, so you must base64-decode it before passing it to eject-js. The custodian backup share is a JSON string (the API returns it JSON-stringified); pass it to eject-js as-is. Only the client share is base64-encoded and needs decoding. Both samples below use this helper for the client share:/v1/recover consumes directly; only eject-js needs it base64-decoded, so decode at eject time.Prerequisites
- Install the eject package:
npm install @portal-hq/eject-js. - A Custodian API key. The endpoints below are Custodian API endpoints and must be called from your backend - never expose a Custodian API key in client code.
- For the Portal-Managed Backups flow, your environment must have Portal-Managed Backups enabled. If it is not, the
ejectable-backup-sharesendpoint returns a400.
With Portal-Managed Backups
With Portal-Managed Backups, both backup shares are stored (encrypted) with Portal. To eject a wallet’s private key, fetch both shares from the Custodian API and combine them:- Custodian Backup Share - returned already decrypted by Portal, ready to pass to eject.
- Client Backup Share - returned as
encryptedClientBackupShare, which is the ciphertext your application produced at backup time. You must decrypt it before combining, reversing the encryption your application applied when it backed up the wallet.
- Get the Portal client’s details and find their
SECP256K1andED25519wallets. - Fetch each wallet’s ejectable backup shares (
encryptedClientBackupShare+custodianBackupShare). - Decrypt each
encryptedClientBackupShare(see the note below). - Combine each pair of shares to recover the private keys.
decryptClientBackupShare is a placeholder for your own decryption logic. With the Enclave MPC API, your application encrypts the client backup share itself at backup time - Portal has no built-in backup method here and only stores the ciphertext you give it. Eject must therefore reverse that same encryption with the same key. If you followed the recommendation in Back up a wallet and used a KMS with envelope encryption, decrypt using that same KMS key. The custodianBackupShare is returned already decrypted and needs no such step.If you stored the whole { share, id } object returned by /v1/backup (rather than just the share string), take its .share field before calling decodeClientBackupShare.SECP256K1 is the curve used by Ethereum and ED25519 is the curve used by Solana.You can learn more about signing algorithms and curves here.With Self-Managed Backups
With Self-Managed Backups you store both backup shares yourself during backup. The eject transforms are the same as above; only the fetch location differs - you read both shares from your own backend instead of from Portal.- Client Backup Shares - the client backup shares you stored. Decrypt them (reversing whatever encryption you applied at backup) and base64-decode them, exactly as in the Portal-Managed flow.
- Custodian Backup Shares - the custodian backup shares delivered to your backup webhook as a JSON string. Pass them to eject as-is.
Using the ejected keys
The recoveredSECP256K1 key (hex) can be imported into most third-party wallets - for example, MetaMask’s private-key import.
The ED25519 key (base58) is a valid Solana key, but it is not directly importable into most third-party Solana wallets: a nuance of MPC distributed key generation for ED25519 prevents it. Portal’s open-source scalarwallet.org (self-host or hosted) lets you use it. See Eject for more detail.