Identity Model
Decentralized identity
Section titled “Decentralized identity”xNet uses self-certifying identifiers — your identity is derived from a cryptographic key pair, not assigned by a server. No registration, no email, no password. You generate a key pair and that’s your identity.
DID:key
Section titled “DID:key”Every user is identified by a DID (Decentralized Identifier) in the did:key format:
did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doKThis DID is derived from the user’s Ed25519 public key:
- Take the 32-byte Ed25519 public key
- Prepend the multicodec prefix
0xed01(Ed25519 identifier) - Encode with base58btc (multibase prefix
z) - Prefix with
did:key:
The public key is embedded in the DID itself. To verify a signature, you parse the DID to extract the key — no external resolver, blockchain, or directory service is needed.
Key pairs
Section titled “Key pairs”Each user has two key pairs:
| Key | Algorithm | Purpose |
|---|---|---|
| Signing key | Ed25519 | Sign changes, UCAN tokens, Yjs updates |
| Encryption key | X25519 | Key exchange, encrypt private data |
The DID is derived from the signing public key. Both keys are bundled together as a KeyBundle and stored encrypted on the device.
UCAN authorization
Section titled “UCAN authorization”UCANs (User Controlled Authorization Networks) are self-signed capability tokens. They replace traditional API keys, OAuth tokens, and ACL systems with a decentralized model where any user can grant capabilities to any other user.
Token structure
Section titled “Token structure”{ iss: "did:key:z6Mk...", // Issuer aud: "did:key:z6Mk...", // Audience (who can use this token) exp: 1706003600, // Expiration (Unix seconds) att: [ // Capabilities granted { with: "xnet://doc/123", can: "write" }, { with: "xnet://doc/*", can: "read" } ], prf: [], // Proof chain (parent tokens) sig: Uint8Array // Ed25519 signature}Delegation
Section titled “Delegation”UCANs support transitive delegation. Alice can grant Bob access, and Bob can delegate a subset of that access to Carol:
Alice → Bob: { with: "xnet://doc/123", can: "write" }Bob → Carol: { with: "xnet://doc/123", can: "read" } (proof: Alice's token)Each token in the chain is self-verifying — you extract the issuer’s public key from their DID and check the signature. No server lookup required.
Capability model
Section titled “Capability model”- Resources are identified by URI:
xnet://doc/123,xnet://doc/*,* - Actions are strings:
read,write,*(wildcard) - Wildcards grant broad access; specific URIs grant narrow access
How identity flows through xNet
Section titled “How identity flows through xNet”- App startup — Key bundle loaded from encrypted storage, identity provided via
XNetProvider - Data mutations — Every
mutate.create()/mutate.update()signs aChange<T>with Ed25519 - Rich text editing — Yjs updates are signed as
SignedYjsEnvelopebefore broadcast - Sync — Remote peers verify all signatures before applying changes
- ClientID binding — Yjs clientIDs are cryptographically bound to DIDs via attestations
No accounts, no servers
Section titled “No accounts, no servers”The identity system has no concept of “creating an account” or “logging in” to a server. Identity is:
- Generated locally — a random Ed25519 key pair
- Self-certifying — the public key is the identity
- Portable — export your key bundle and use it on any device
- Verifiable offline — signatures can be checked without network access
Further reading
Section titled “Further reading”- Identity & Keys Guide — Practical API usage
- Cryptography — The primitives behind identity
- Sync Guide — How signed updates propagate