Identity and recovery evidence — 2026-07-15
Issue: #8
Baseline commit: 0843833
Exact package: jazz-tools@2.0.0-alpha.53
Decision
Reject BrowserPasskeyBackup from the M1 product contract. Do not invoke it, present it as backup,
or run real-device ceremonies until Jazz changes the storage design or provides a security argument
that satisfies the WebAuthn user-handle model.
This is a security kill before the device matrix, not a claim that the physical flows passed. The stable HTTPS device site explicitly says passkey backup is blocked.
Source finding
Retained installed-source hashes:
e9dcea8ed17538cc9e58f7a97d74c8ff719336e3db1f26a7f44d6ed9f25688df passkey-backup.js
c95327809b841996f5fd12b7f740ebc09b0771f4e95f9cf69dcd385dc589b747 recovery-phrase.js
BrowserPasskeyBackup.backup() decodes the 32-byte Jazz auth secret and assigns those bytes
directly to PublicKeyCredentialUserEntity.id. restore() returns assertion userHandle as the
same auth secret. No encryption, wrapping key, large-blob encryption, or server-held recovery record
exists in this path.
WebAuthn Level 3 says user handles are account identifiers, must not contain personally identifying information, and may be revealed by authenticators without prior user verification. A full-control Jazz auth secret has a stronger confidentiality requirement than the field WebAuthn defines. See §14.6.1 User Handle Contents.
The implementation requests a platform discoverable credential, required user verification, and the
credProtect extension, then verifies UP/UV flags on restore. Those are useful ceremony controls but
do not redefine user.id as secret storage. The package also:
- ignores the credential returned by
credentials.create()and records no credential ID; - treats a resolved
nullcreate result as success; - records no backup-eligibility or backup-state signal, so it cannot prove ecosystem sync;
- supplies no exclude list, list, has, delete, or clear-passkey operation;
- can create duplicate credentials on repeated backup;
- returns a restored secret but leaves saving it and recreating the database to the caller.
Accurate identity model
| Action | Exact meaning |
|---|---|
| First visit | Generate a random 32-byte auth seed and keep it in namespaced browser localStorage. |
| Clear site data | Remove the local seed and OPFS state; the next boot creates a different identity. |
| “Sign out” helper | Clear and regenerate the seed, so this is identity rotation, not a logged-out state. |
| 24-word phrase | Reversible BIP39 encoding of the same seed; no password, KDF, encryption, reset, revocation, or rotation. |
| Restore identity | Save the recovered seed and recreate the database/client. It does not restore unsynced OPFS rows. |
Both a future safe passkey mechanism and the phrase recover identity authority only. Data lost with site storage returns only when it was separately synced and remains readable by that identity.
Product wording
Use:
- “This device has a local identity key.”
- “Passkey backup is unavailable in this alpha because it did not pass security review.”
- “The 24 words are a full-control bearer secret. Anyone with all words can act with this identity.”
- “Identity recovery is not data backup. Unsynced device data cannot be recovered.”
- “Without a verified recovery method, clearing site data can permanently lose access.”
Do not use “passkey-only account,” “login,” “cloud backup,” “sign out,” or “data recovery” for the current behavior.
First-run and recovery UX decision
M1 creates the local identity without a network round trip and immediately states its device-local custody. Passkey backup controls are absent. A phrase export/import UI is deferred until it can provide deliberate reveal/confirmation, prevent logging or telemetry, and make the bearer-secret and identity-only limits unavoidable. Until then the prototype is honest but unrecoverable after site-data loss.
Deferred device matrix
Fresh profile, deleted passkey, same-ecosystem restore, cross-platform restore, iOS tab/Home Screen, and Android browser/installed-app passkey cases are not run because the candidate mechanism failed the pre-device security gate. Reopen the matrix only for a replacement mechanism with a confidential secret-wrapping design and explicit RP-ID contract.
Contract delta
DX-AUTH-01 is revised: M1 validates truthful local-identity wording and rejects the alpha passkey mechanism. DX-DEVICE-01 remains required for OPFS/PWA testing, but no unsafe passkey ceremony is performed merely to fill a matrix.