clone

a deno framework for local-first web apps that open instantly, work offline and sync when users choose

main
lofi / docs / spikes / identity / evidence / 2026-07-15.md
2026-07-15.md 5.2K source

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 null create 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

Status as recorded at M1, scoped to the rejected alpha mechanism. The replacement recoverable passkey mechanism has since shipped and validated DX-AUTH-01/DX-DEVICE-01; do not cite this deferral as current status.

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.