Identity
What a ghost ID is, where it lives, and why reset is not logout.
A Ghost identity is a stable ID with one active browser credential. The
credential's private key is a non-extractable CryptoKey in IndexedDB.
The Ghost ID is the durable application handle:
ghost_1_crhgcniramqtgfpib5uiaautocwdigbt
└───┬──┘└──────────────┬───────────────┘
version stable identity material,
prefix hashed and base32
The ID is URL-safe, case-safe, and versioned — the 1
names the exact cryptographic suite, so the scheme can evolve without
ambiguity. Full byte-level detail lives in the
protocol reference.
The active credential has its own ID:
cred_1_3dveqtnobb556nsxhfyhh6qbn5lhsseb
Proofs authenticate the credential. Your application stores which credentials are active for a Ghost, so recovery can rotate to a fresh non-extractable key without changing the Ghost ID.
One origin, one identity
An identity belongs to a browser profile and an origin, because that is
how browser storage works — and Ghost treats it as a feature. The same
browser gets a different, unlinkable ghost on app-a.example and
app-b.example. There is no universal identifier following anyone across
the internet; Ghost is pairwise by default.
Ghost is pseudonymous, not anonymous. Your application can still link a ghost to an IP address, behaviour, or anything a user types. Ghost adds no tracking — it also cannot subtract any.
Durability and recovery
Without recovery, the local credential is exactly as durable as the origin's storage:
- Clearing site data destroys it.
- Browser resets, profile loss, and storage eviction destroy it.
- Private browsing windows get an identity that dies with the window.
- If recovery was never enabled, the Ghost may be unrecoverable.
Recovery is opt-in. Calling ghost.enableRecovery() creates a user-held
recovery secret and an app-stored recovery record. Later,
recoverGhost({ recoverySecret, recoveryRecord }) verifies the secret and
generates a fresh local non-extractable credential for the same Ghost ID.
No email, password, OAuth provider, Ghost-hosted account, or automatic cloud backup is involved. If the user loses both the browser credential and the recovery secret, Ghost cannot reconstruct the identity.
Reset is not logout
await ghost.reset();reset() deletes the local key. The old identity becomes permanently
inaccessible from this browser, and the next createGhost() mints a fresh
one unless the user recovers with a previously saved recovery secret. It is
deliberately not called "logout": there is no account to log out of.