DocumentationBuild. Deploy. Operate.
DocsConcepts

Identity Gate

On this page 6 sections

Per-request identity enforcement, bound to the substrate rather than to the browser.


Why

Traditional web authentication hands the user a stealable secret, a cookie or a bearer token, and trusts the client to present it on every request. QSCS rejects that model. There are no cookies, no bearer tokens, and no localStorage credentials. Identity is a property of the substrate connection between the browser and the node, expressed as an ed25519 signature over every authenticated request.

Components

  • WASM substrate, a 17 KB module loaded into the browser. It generates an ed25519 keypair on first visit, persists the private key in IndexedDB wrapped under a non-extractable AES-GCM key, and exposes a single export, qscs_sign_request, that signs a canonical request representation. The private key never leaves the WASM linear memory; the JS host has no DOM access to it.
  • Signed fetch shim, qscs-crypto.js monkey-patches window.fetch. Every same-origin request is augmented with four headers: X-QSCS-Client-Uuid, X-QSCS-Ts, X-QSCS-Nonce, and X-QSCS-Sig.
  • QSCSCore gate, the HTTP listener verifies the signature against the public key the client supplied at login. Replay protection: each (UUID, nonce) tuple is accepted only once, and timestamps must fall within a ±60 s window.
  • PHP defence-in-depth, PHP endpoints that previously gated themselves on a database flag now require an X-QSCS-Identity header that QSCS injects only for verified requests. PHP strips any client-supplied value before checking.

Canonical Message

The string signed by qscs_sign_request is constructed as:

METHOD 
 HOST 
 URI 
 BODY 
 TS_MS 
 NONCE_HEX

Both client and server build this representation identically. The server then verifies the ed25519 signature using the public key stored against the client UUID at /auth/login time.

Lifecycle

  1. Browser loads page, fetches /wasm/qscs-substrate.wasm, instantiates it.
  2. WASM either loads an existing wrapped blob from IndexedDB or calls qscs_identity_generate to create one.
  3. User submits the login form. The POST to /auth/login is signed; the body carries username, password, client_uuid, and pubkey.
  4. QSCSCore verifies the signature against the supplied pubkey (proof of possession), then forwards the credentials to the control plane for validation.
  5. On success, QSCSCore stores (client_uuid, origin, pubkey) in its SpookDB identity table and replicates the binding to peers via the existing identity delta channel.
  6. Every subsequent fetch is signed; the gate verifies and forwards. Other origins, other UUIDs, and unsigned requests are rejected with HTTP 401.

Failure Modes & Responses

ConditionHTTP statusResponse body
Missing or malformed signature headers401{"error":"identity signature required"}
Timestamp outside ±60 s window401{"error":"identity signature required"}
Nonce already seen for this UUID401{"error":"identity signature required"}
Signature does not verify against stored pubkey401{"error":"identity signature required"}
Client UUID unknown to this node401{"error":"identity signature required"}

All failure paths emit an identical client-visible message; the discriminating reason is logged server-side only.

Need a hand with your deployment?Contact support ↗Back to top ↑