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
| Artifact | Stays on device | Sent to relay | In object store | Visible as metadata |
|---|---|---|---|---|
prepareNewDeviceTransfer() qrCode | yes | no | no | no |
Backup from sending.getBackup(sessionIds) | yes | encrypted, if routed that way | optional, encrypted | size and write time |
| Backup encryption key | yes, or user-held | no | no | no |
identityKeyPair private half | yes | no | no | no |
identityKeyPair public half | yes | yes | no | yes |
Session records (version: 4) | yes | no | no | no |
| Prekeys (private halves) | yes | no | no | no |
| Prekeys (public halves) | yes | yes | no | count and consumption rate |
| Decrypted message rows (app-owned) | yes | no | no | no |
rotateAccountIdentity() commitment | yes | yes | no | yes — the relay sequences the swap |
| Recovery attempt audit records (app-owned) | yes | no | no | no |
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
- Multi-device: use the provisioning path that does not carry history
- Deletion and revocation: understand deletion operations
- Threat model: select one of the three profiles
- Production checklist: verify this decision before launch
Identity changes and safety numbers
Generating safety numbers, handling identity-key change errors, and designing a verification experience that users can actually complete.
Operate
Running an encrypted application in production — what you can measure without plaintext, what rotates on its own, what fails silently, and what a security reviewer will ask for.