Skip to content

Identity & app keys

This content is for the 0.2.0-alpha.3 version. Switch to the latest version for up-to-date documentation.

There are two kinds of “identity” in Muhkoo, and they answer different questions.

A user’s identity is derived on their device from (username, password):

seed = PBKDF2(password, "muhkoo-zk-v1:" + username)
secret = HKDF(seed, "zk-secret")
salt = HKDF(seed, "zk-salt")
…plus deterministic ECDSA + ECDH keypairs
commitment = Poseidon(secret, salt, Poseidon(ecdsaPub))

The accelerator only ever stores the commitment — a one-way Poseidon hash. At login the client proves, in zero knowledge (a Groth16 proof over the preimagePoK circuit), that it knows a (secret, salt, …) matching the stored commitment, without revealing any of it.

Consequences:

  • No passwords or secrets on the server. Ever.
  • Federated login. The same (username, password) reproduces the same identity (and commitment) on any device — no key material to sync or escrow.
  • The commitment is the user’s stable id — it’s what user.commitment returns and how per-user data is addressed.

Your app authenticates to the accelerator with an app key. Keys look like:

mk_<env>_<type>_<32 hex>
│ │
│ └ sk = secret key (server-side) pk = publishable key (browser-safe)
└ live | test
  • pk (publishable) — safe to ship in client bundles. Use this in new Client({ apiKey }) for browser apps.
  • sk (secret) — server-side only. Never put it in a browser bundle or any client-exposed env var.
  • test vs live — separate environments. Test keys exercise the full stack without touching live billing/usage.

Keys are issued per app from the developer portal (or POST /api/apps). They’re per-deployment — a key minted against one accelerator (e.g. staging) won’t resolve on another (e.g. production).

  • Billing + metering — usage is attributed to the app behind the key.
  • Messaging — shared-space (space/DM) websockets are authorized with a short-lived ticket derived from the app key.

A request carries the app key (which app) and, once a user signs in, the session token (which user). Authorization is the intersection: this app, acting for this user. CORS is wildcard because the API is public and multi-tenant — security rides on the keys, not the origin.