OpenE2EE

Recovery, backup, and migration

Three named threat-model profiles for the "lost device" question, the SDK operations that support each, and why there is no correct default.

Status
pre-1.0
Applies to
0.1.0
Platforms
Expo · Browser · Node
Prereqs
A working client from Start → Quickstart
Reading time
15 min

"If the user loses their phone, is their data gone?"

Most teams have never had to answer this, because the server always had a copy. Under end-to-end encryption it becomes a product decision with no correct default. This page gives you three named positions, states what each one costs, and points at the operations that implement them. It does not pick one, because the SDK does not pick one either.

What the SDK moves, and what it does not

Two operations exist, and they carry different data. Provisioning a linked device transfers identity material and optional metadata. It transfers no sessions or message history. Transfer to replacement hardware migrates local cryptographic state, including identity keys, prekeys, and sessions, via an encrypted backup:

import {
  prepareNewDeviceTransfer,
  prepareOldDeviceTransferWithBackup,
} from '@open-e2ee/signal-protocol-sdk/device';

const receiving = await prepareNewDeviceTransfer();
await appQr.show(receiving.qrCode);

const sending = await prepareOldDeviceTransferWithBackup(backupStorage);
const backup = await sending.getBackup(sessionIds);

This path requires the old device. Device-to-device transfer supports an upgrade, not recovery after loss. A phone in a canal cannot participate.

Your application must build recovery for a device that never held the state. This process restores from a source other than the old device. You decide where the material lives, who can access it, and which authentication it requires.

Why recovery is structurally hard

Engineering cannot remove this conflict. 1Password states it directly:

"Recovery mechanisms are inherently weak points in maintaining the secrecy of data."

A recovery path for a user who lost all devices can also become an attack path.

Signal Messenger uses a 64-character recovery key:

"Signal cannot recover, reset, or bypass"

If a user loses the key, Signal cannot recover it. Earlier, Signal used secure enclaves to let a PIN open Secure Value Recovery material. That design received significant criticism. Matthew Green described the expansion risk:

"Nobody is going to engineer something as complex as Signal's SVR just to store contact lists. Once you have a hammer like SVR, you're going to want to use it to knock down other nails."

The mechanism creates risk regardless of its first use.

The industry has not settled this question. Meta shipped Labyrinth 1.1 in May 2026, two and a half years after Messenger enabled end-to-end encryption by default. The change sends messages to encrypted backup:

"as they're sent, rather than waiting for your device to come back online."

Meta continues to change how messages survive a lost phone.

Three profiles

Select one profile deliberately. Each profile protects different properties.

Profile: business-archive

A server-confidential business archive preserves history after device loss, staff turnover, and hardware replacement. Its purpose is continuity across devices.

Protects: message content against relay compromise, infrastructure breach, and bulk disclosure because the storage layer holds ciphertext. Backups mean a lost laptop is an inconvenience rather than a data-loss event.

Gives up: coercion resistance. An authority can compel use of a durable recovery path. An attacker can socially engineer it, and an insider can misuse it. These attacks depend on access to the authentication in front of the path. This profile also gives up "nothing to hand over" as a posture. You must monitor and rate-limit this permanent, high-value attack surface.

Suits: internal business communication, regulated professional services where records must persist, and any product where losing history is worse than the extra exposure.

You implement: an encrypted backup artifact and its key hierarchy. Add strong recovery authentication and audit every recovery attempt, including failures. Define how operators detect that "an administrator triggered a recovery."

Profile: high-risk-messaging

This profile limits recoverable history by design. A lost device means lost history.

Protects: users against compulsion, seizure, and later access. An adversary cannot access a durable artifact. Current device content bounds retention. This design also reduces the content that an authority can compel your organization to produce.

Gives up: continuity, and it generates support load. Users will lose history and some of them will be angry, because every other application they use restores silently. Expect this to be your most common support category.

Suits: journalism, activism, legal-privileged and source-protection contexts, and consumer products whose promise is explicitly ephemerality.

You implement: define and enforce a retention policy. During onboarding, tell users that device loss removes history. Provide export flows for users who still have the device and need a record.

Profile: collaboration-default

A middle position, and explicitly a compromise. It balances offline work, recoverability, and membership change for teams that are neither an archive nor a threat-model product.

Protects: recent working context. A replaced laptop recovers enough to keep working, and offline devices reconcile without a full history refetch.

Gives up: it does not guarantee that an eighteen-month-old message survives. Therefore, it cannot be the system of record. It also retains a recovery path, so it resists coercion less than high-risk-messaging. It provides part of each property, not all of either property.

Suits: team collaboration tools, product and engineering workspaces, customer communication where a separate system already holds the durable record.

You implement: define a retention period and enforce expiry. Limit recovery to that period. Clearly separate "your messaging history" from "your system of record" before an audit.

Operations you have

await signal.clearAllData();

clearAllData() wipes local protocol state. It completes only the local part of an account reset. Account reset must clear the device-ID cache, platform secret storage, and protocol store as one product-level lifecycle. Doing one and not the others leaves a device with a cached identity claim it can no longer back.

forceCompleteKeyReset() regenerates keys with fresh IDs and republishes them. The SDK marks it for development and debugging only. Treat it as a break-glass tool, not part of a user recovery flow.

rotateAccountIdentity(expectedCurrentCommitment, identityType) is the deliberate identity rotation, guarded by a caller-authenticated compare-and-swap against the 32-byte commitment you expect to be current. Normal sync and linked-device provisioning never call it. Rotating an account identity is visible to every peer as an identity change. See Identity changes and safety numbers. This recovery operation has a visible social cost.

Deletion is not remote deletion

Encryption does not give you a delete button on someone else's device. After another participant gets a decrypted copy or stores it in a backup, cryptographic confidentiality creates no remote deletion guarantee. You can stop serving an envelope. You cannot reach into a peer's local store, and any product copy suggesting otherwise is a promise you cannot keep.

The same applies to your own backups. A message deleted from a thread today is still in an archive written yesterday, unless you built the process that reconciles them.

Opacity ledger

ArtifactStays on deviceSent to relayIn object storeVisible as metadata
prepareNewDeviceTransfer() qrCodeyesnonono
Backup from sending.getBackup(sessionIds)yesencrypted, if routed that wayoptional, encryptedsize and write time
Backup encryption keyyes, or user-heldnonono
identityKeyPair private halfyesnonono
identityKeyPair public halfyesyesnoyes
Session records (version: 4)yesnonono
Prekeys (private halves)yesnonono
Prekeys (public halves)yesyesnocount and consumption rate
Decrypted message rows (app-owned)yesnonono
rotateAccountIdentity() commitmentyesyesnoyes — the relay sequences the swap
Recovery attempt audit records (app-owned)yesnonono

The SDK versions session records. It rejects and resets older formats instead of migrating them. A backup from an older build can therefore contain an incompatible session. Plan for the SDK to discard and recreate that session instead of resuming it.

This surfaces after launch

Device loss often occurs after a beta. Replacement cycles, water damage, and theft operate over months. The recovery question can therefore arrive after you set the architecture. Changing profiles then requires migration between incompatible user expectations.

Decide before launch, and write the chosen profile name down. When someone later proposes a feature that quietly moves you between profiles, that written decision is what makes the conversation possible.

0.1.x; public APIs and persisted formats may change before 1.0.

Next

On this page