Accounts and recovery — an account only its owner can open
A Witbitz account is the user's own: everything in it is sealed under keys made on the user's device, the server keeps only ciphertext, and Witbitz cannot open it or recover it on anyone's behalf. This page is how an account is made, how it reaches every device, and how it comes back when every device is lost.
Status: Production in the Spaces app (regular and hosted) and in the SDK.
What an account is
- An identity: a verified email. The user proves the address with a one-time email code or Google. The same email is a separate account in each app — an app built on Witbitz cannot see or touch the user's account in another.
- A root: the master secret. 32 random bytes made on the device when the account is created. Every other account key is derived from it or sealed under it. It never leaves the device in the clear.
| Key | Made | Used for |
|---|---|---|
| Master secret | on the device, at creation | the root: derives the keys below and seals the backup |
| Account store key | derived from the master | seals the account's own records (the room list) on the device |
| Account signing key | on the device | signs this account's device certificates |
| Invite key | on the device | lets others invite this account by email: only its public half is published, under a blinded handle |
| Room keys | on the device, one per Space | open each Space |
Creating an account
- On a computer, secure it first. Before anything personal is written, the user sets up one passkey that is both this computer's lock and the account's backup passkey. A computer that cannot hold such a passkey uses the phone instead (by QR).
- Prove the email. A one-time code or Google. If the address already has an account, the user is offered to restore it instead of starting a duplicate.
- The device makes the account. The master secret and a recovery code — 128 random bits, shown as groups of letters and digits — are made on the device. The encrypted backup is written, then the recovery gate is set up (below).
- Keep the code. The app shows the recovery code to copy and keep somewhere safe, and offers to add a backup passkey.
One account on every device
The account's room list — every Space with its key and name — lives in a hidden index room, sealed on the device under the account store key before it is written: the server stores it and cannot read it. Two more hidden rooms hold the private assistants' links and messages between the user's own devices.
A new device needs only the master secret: from it, the backup gives the index room's address and key, and the index room gives every Space. Changes reach the other devices through the index room as they happen.
Add a device without the recovery code: on a device that is already signed in, confirm with its passkey and show a QR code; the new device scans it, and the master, the code and the sign-in are sealed to the new device's own key and passed through a two-minute relay.
The encrypted backup
| What it holds | the account's keys (signing, invite), the index room's address and key, the Spaces' keys, contacts, connection handles, the recovery code (so the app can show it again) |
| Sealed with | AES-GCM under a key derived from the master secret, on the device |
| Stored at | an id also derived from the master — without the master, nobody can find it or read it |
| Written | a few seconds after a change, merged with the stored copy |
The master itself is stored only wrapped — once under the recovery code, and once under the backup passkey (its WebAuthn PRF secret). Either wrapper opens it on the device.
Recovering an account
The backup is behind a gate that asks for two things — so neither a leaked recovery code nor a hijacked mailbox opens the account alone.
| What the user has | Opens the account? |
|---|---|
| Recovery code + the account's email (a one-time code, or Google) | Yes — the usual way back after losing every device. It also signs the new device in. |
| The backup passkey | Yes — the passkey made with the account, or one added after an email check, is a factor of the gate by itself. |
| Another signed-in device | Yes — Add a device, above. |
| The recovery code alone | No, for any account created signed in. |
| The email alone | Never. |
How the gate checks the email without learning it. The gate stores only an HMAC of the email under a key derived from the recovery code. At recovery, the device sends that key with the email check; the server verifies the proven address against the stored value. The code itself never reaches the server, and decryption always happens on the device.
What Witbitz sees and can do
- Sees: ciphertext at opaque ids, their sizes and write times; the gate's record; during a recovery, the email it sends the code to. Short-lived per-IP counters for rate limits.
- Cannot: read the backup, the room list or any Space; recover an account without the user's code, passkey or device. There is no operator key.
- Can: refuse service — withhold a backup, or delete one. Availability is ours to break; reading is not.
Guessing is rate-limited: an emailed code has six digits, expires in ten minutes and allows five tries; every recovery step is limited per IP. A recovery code is 128 random bits.
In your app
- The Spaces app holds the account in the page (regular app), or in the vault (hosted app) — the frame that draws the screen never holds the master or the room keys (the app as an operating system).
- The SDK:
wb.backupis the same backup, one per app, with the email gate when the user is signed in;wb.accountis the live room list. In vault mode your vault holds the account (SDK — account backup, vault mode).
Read next
Machine-readable source: accounts.md · Generated 2026-10-27T07:05:42Z · build f301388c · every doc in one fetch: llms-full.txt (HTML)