๐ŸคนMulti-Backup Migration Guide

Transitioning from MPC version v5 to v6.

What is Multi-Backup?

Multi-backup enhances data security by allowing users to utilize multiple backup methods, ensuring greater resilience and recovery options. In previous versions, recovery attempts could fail if they didn't match the latest backup method used. With multi-backup, users can recover data using any of the methods they've backed up with, such as GDRIVE, ICLOUD,PASSWORD, or PASSKEY.

Key Changes in the Migration

  • Webhook Adjustments:

    • POST /backup: Now includes a "backupMethod" key.

    • POST /backup/fetch: Replaces "backupShare" with "backupShares".

  • API Endpoint Modifications: The POST /stored-client-backup-share endpoint now requires "backupMethod".

  • Database Schema Alterations: To support multi-backup, you may need to modify your database schema.

Applicable SDK Version Upgrades

This guide is applicable for the following SDK upgrades:

Database Changes

Multi-backup requires storing both custodian and user backup shares by their respective backup method. We recommend the following database model structure:

// Encrypted backup share received from portal.backup().
model UserBackupShare {
  backupMethod String       @default("UNKNOWN")           // (String) The method used for the backup. Defaults to "UNKNOWN" if not specified.
  createdAt    DateTime     @default(now())               // (DateTime) The timestamp when the backup share was created.
  id           String       @id @default(cuid())          // (String) A unique identifier for each backup share
  cipherText   String                                     // (String) The encrypted backup share data.
  userId       String                                     // (Int) The identifier of the user to whom the backup share belongs.

  user User @relation(fields: [userId], references: [id]) // (User) A relation field that links to the corresponding user in the User model.

  @@unique([userId, backupMethod])                        // A unique constraint ensuring that each user has only one backup share per method.
}

// Raw backup share received from the POST /backup webhook.
model CustodianBackupShare {
  backupMethod String       @default("UNKNOWN")           // (String) The method used for the backup. Defaults to "UNKNOWN" if not specified.
  createdAt    DateTime     @default(now())               // (DateTime) The timestamp when the backup share was created.
  id           String       @id @default(cuid())          // (String) A unique identifier for each backup share
  share        String                                     // (String) The raw backup share data.
  userId       String                                     // (String) The identifier of the user to whom the backup share belongs.

  user User @relation(fields: [userId], references: [id]) // (User) A relation field that links to the corresponding user in the User model.

  @@unique([userId, backupMethod])                        // A unique constraint ensuring that each user has only one backup share per method.
}

// User model, often referred to as "Client" in documentation.
model User {
  clientApiKey   String  @unique               // (String) The unique Client API Key assigned to the user.     
  clientId       String  @unique               // (String) The unique identifier for the client that Portal uses.
  id             String  @id @default(cuid())  // (String) The primary key for the user

  userBackupShares    UserBackupShare[]    // (UserBackupShare[]) A list of the user backup shares related to the user.
  custodianBackupShares CustodianBackupShare[] // (CustodianBackupShare[]) A list of the custodian backup shares related to the user.
}

For assistance or more details on structuring your database for this migration, please reach out to our team, we are here to help! ๐Ÿ˜Š

Webhook Changes

Before upgrading to multi-backup, update your webhook implementations. These new implementations are backwards compatible. Here's what you need to account for:

POST /backup: This request now includes a backupMethod key. Store the custodian backup share accordingly.

{
  "clientId": "some-client-id",
  "share": "stringified-share",
  // New key-value pair ๐Ÿ‘‡
  "backupMethod": "PASSWORD" // One of: "GDRIVE", "ICLOUD", "PASSWORD", "PASSKEY" (@WARNING: we may add others or modify them in the future)
}

Store the share for the user by backupMethod, since a user can now have a backup share per backup method. If a share already exists for that user with the same backupMethod, delete the old share and keep the new one.

POST /backup/fetch: Expect an array of backup shares in the response, reflecting the user's multiple backup methods.

{
  // "backupShare": "stringified-share" // Removed.

  // New key-value pair ๐Ÿ‘‡
  "backupShares": ["stringified-share", "stringified-share-2", ...]
}

SDK + REST API Changes

  • Storing the Encrypted User Backup Share: After portal.backup(), store the returned cipherText by the backup method that was used in your database.

  • Upgrading the API Endpoint to v2: Use PUT https://api.portalhq.io/api/v2/clients/me/wallet/stored-client-backup-share, providing the backupMethod in the request body. You can provide it in the request body like this:

{
  "success": true,
  // New key-value pair ๐Ÿ‘‡
  "backupMethod": "PASSWORD" // One of: "CUSTOM", "GDRIVE", "ICLOUD", "PASSWORD", "PASSKEY" (@WARNING: we may add others or modify them in the future)
}
  • Retrieving the User Backup Share: Update your retrieval process to match the backup method used in portal.recover().

  • Update isMultiBackupEnabled feature flag: Update the feature flag isMultiBackupEnabled to true when instantiating Portal.

new Portal({
  ...,
  featureFlags: {
    ...,
    isMultiBackupEnabled: true,
  },
})

You did it! ๐Ÿ™Œ You've successfully navigated the intricacies of enabling multiple backups for your users. Please reach out if you have any questions or if we can assist in any way.

Last updated