Skip to main content

Portal-Managed Backups

Portal lets you securely back up your users’ MPC wallets so they can recover their wallets even if their device is lost or damaged. By default, Portal encrypts and stores both backup shares (“Portal-Managed Backups”):
  1. The client backup share is encrypted on the user’s device, with the encryption key stored using their chosen backup method (Google Drive, Password, Passkey, or Firebase Auth). The encrypted share is then stored by Portal.
  2. The custodian backup share is encrypted and stored by Portal, with the encryption key stored in our KMS infrastructure.
By default, Portal manages storing both the encrypted client backup share and the custodian backup share for you. If you prefer to store and manage the backup shares in your own infrastructure instead of using Portal-Managed Backups, see our Self-Managed Backups guide.
Both the client backup share and the custodian backup share are necessary to recover a Portal wallet.

Backup Methods

You can choose one or more backup methods for storing the encryption key for the client backup share.

Passkey + Enclave

Your Portal clients can create a passkey to authenticate and manage the private encryption key within a secure enclave.

Implementation Requirements

  1. Initialize the Portal class with a passkey object.
  2. Call backup with the Passkey backup method argument.

Custom Domain Passkeys

By default, Portal handles passkey operations through our hosted domain (portalhq.io). If you want passkeys to be associated with your own domain (e.g., yourapp.com), you can configure a custom relying party. Benefits of using your own domain:
  • Passkey prompts display your domain name instead of Portal’s
  • Users see a consistent brand experience
  • Passkeys are portable across your applications that share the same relying party
Setup Requirements
To use your own domain for passkeys, you’ll need to:
  1. Configure DNS - Point your passkey subdomain (e.g., passkeys.yourapp.com) to Portal’s infrastructure
  2. Provision a TLS certificate - Create a certificate for your subdomain that Portal will store in our secure enclave
  3. Configure CORS - Allowlist your application origins
Getting Started: Reach out to the Portal team for instructions on setting up a custom domain, including TLS certificate provisioning for our enclave.
Configuration
Once your custom domain is set up, configure your passkey options:
Step 1: Create a Passkey
Create a passkey for your user. This can be done separately from the backup flow:
Step 2: Create a Backup
Once a passkey exists, you can create a backup and store the encryption key with it:

Password/PIN

Your Portal clients can create a password/PIN. They can either remember the password or store it in a password storage manager.

Implementation Requirements

  1. Create a UI for password input.
  2. Enforce password requirements. Customer can choose between password, PIN code, passcode, or any other text-based input.
  3. If the user forgets their password, there are no additional recovery options.

Google Drive

Your Portal clients can store the encryption key in their own Google Drive. When a backup or recovery needs Drive access, the SDK asks the user to choose a Google account and grant the Drive scopes your configuration needs.

Implementation Requirements

  1. Set up Google Drive in a Google Cloud project and create an OAuth client ID of type Web application. Google sign-in runs in the Portal iframe, so Google checks the iframe’s origin, not your app’s: under Authorized JavaScript origins, add https://web.portalhq.io, or your custom subdomain, such as https://portal.yourdomain.com, if you set host.
  2. Initialize the Portal class with a gdrive object containing the OAuth clientId and, optionally, a backupOption.
  3. Once the SDK is ready, call backup with the Google Drive backup method argument from a user action, such as a button click.

Choose where backups are stored

Starting in 4.2.0, backupOption decides where the SDK writes backups and where it looks for them: The scopes are https://www.googleapis.com/auth/drive.file and https://www.googleapis.com/auth/drive.appdata. Omitting backupOption keeps the behavior of earlier SDK versions. Any other value throws from the Portal constructor. appDataFolderWithFallback reads the user-visible Drive only when the app data folder has no backup. If Drive returns an error while the SDK looks for the backup, recovery fails with that error instead of falling back.

Share backups with your iOS and Android apps

To recover on one platform a backup made on another, every platform needs OAuth clients from one Google Cloud project, the same backup location and the same Google account. Share backups across platforms in the GDrive setup guide explains why and lists the equivalent option on each platform. On the web:
  • Create your web OAuth client in the same Google Cloud project as your iOS and Android OAuth clients, whichever backupOption you use.
  • Match the location your other apps use. The Web SDK defaults to the user-visible folder, while the iOS and Android guides use the app data folder. With those settings, a backup made on iOS or Android is not found on the web. To share backups with those apps, set backupOption to 'appDataFolder', or to 'appDataFolderWithFallback' if your users already have web backups and won’t later recover with an option or app that reads only the user-visible folder (see Change the backup location for existing users). The React Native SDK only uses the user-visible folder, so keep 'gdriveFolder' to share backups with a React Native app.

Change the backup location for existing users

Changing backupOption doesn’t move or delete existing backups. The SDK only looks where the new option tells it to: Web SDK versions earlier than 4.2.0 only use the user-visible folder, so they can’t read backups written to the app data folder. A new backup also replaces the user’s previous one without deleting its file: after a user with a user-visible backup backs up in the app data folder, the older user-visible file holds a key that no longer matches their wallet. Recovery that reads only the user-visible folder, with 'gdriveFolder' or a Web SDK earlier than 4.2.0, can find that file and fail with Failed to decrypt (error code 407), and other apps that only use the user-visible folder, such as a React Native app, can find it too. So once users have backed up with 'appDataFolder' or 'appDataFolderWithFallback', don’t move them back to 'gdriveFolder' or to an earlier Web SDK version.
Recovery fails with [GDriveStorage] File could not be found. when there is no backup file where the configured backupOption looks, even if a backup exists elsewhere: in the user-visible folder while you use 'appDataFolder', in the app data folder while you use 'gdriveFolder' or a Web SDK earlier than 4.2.0, in the app data folder of a different Google Cloud project, or in a different Google account. If it finds an older user-visible file instead, recovery fails with Failed to decrypt (error code 407).

Google sign-in and sessions

  • Pop-ups: Google sign-in opens in a pop-up window. The Portal iframe opens it, not your page, so browsers can block it even when the backup or recovery starts from a click. Chrome blocks it with its default settings; allowing pop-ups for your site, then reloading the page, lets it open. In 4.2.0 a blocked pop-up isn’t reported: backupWallet or recoverWallet fails only when the SDK’s request times out, after 90 seconds.
  • Declined scopes: Google’s consent screen lets users untick individual scopes. If a scope the backupOption needs is not granted, the backup or recovery fails with [GoogleAuth] The user did not grant the required Google Drive scopes: followed by the scope URLs. Starting in 4.2.0 this applies to every backupOption, including the default.
  • Sessions: an open page keeps using the Google access token it already has. After a page reload, Google sign-in can be reused for up to five minutes when the Portal iframe is on the same site as your app, for example with a custom subdomain. The SDK keeps that session in cookies on the iframe’s origin. With the default iframe host, which is on a different site from your app, browsers may not keep these cookies, so users may be asked to choose their Google account again after a reload.
  • Scope changes: a saved session is reused only if it covers the scopes the current backupOption needs, so after you change backupOption the user may be asked to sign in again. Users who signed in with a Web SDK earlier than 4.2.0 may also be asked to choose their Google account again after you upgrade.

Drive errors

Starting in 4.2.0, if Google Drive returns an error while the SDK looks up, creates or uploads the backup file, backupWallet rejects with Drive’s error code and message, for example [GDriveStorage] Error writing file: 403 …, and the backup is not recorded as stored. Earlier versions could report a backup as complete even though the upload failed.

Firebase Auth Backup

Allow customers to use their existing Firebase Authentication to authenticate into a secure enclave that holds the encryption key for the user. The Portal Web SDK uses Firebase ID tokens to store and retrieve encryption keys from Portal’s Trustless Backup Service (TBS). This is ideal if your web app already uses Firebase Auth, since your users need no additional authentication method. See the Firebase Auth Backup setup guide for prerequisites and Firebase project configuration.

Implementation requirements

  1. Integrate Firebase Authentication in your web app (for example with the Firebase JavaScript SDK).
  2. Call portal.configureFirebaseStorage with a getToken callback that returns a Firebase ID token for the signed-in user, or null when no user is signed in.
  3. Run backup with BackupMethods.firebase only after Firebase storage is configured and the user is signed in.
Unlike React Native, the Web SDK does not use a separate @portal-hq/firebase-storage package. Firebase backup is built into @portal-hq/web via configureFirebaseStorage. Your app supplies Firebase Auth; the Portal iframe requests ID tokens from the parent page through a secure postMessage bridge.

Configure Firebase storage

Call configureFirebaseStorage before backupWallet or recoverWallet with BackupMethods.firebase. You typically do this immediately before the backup or recovery flow, or once after the user signs in to Firebase.
The user must be signed in to Firebase before running backup or recovery. If there is no signed-in user, getToken should return null and the operation will fail.
The tab examples below assume a portal instance and configureFirebaseForPortal helper from the Configure Firebase storage section above.
Ensure the user is signed in to Firebase, configure storage, then run backup. With Portal-Managed Backups (the default), Portal stores the encrypted client backup share for you.
Related documentation