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.jsmonkey-patcheswindow.fetch. Every same-origin request is augmented with four headers:X-QSCS-Client-Uuid,X-QSCS-Ts,X-QSCS-Nonce, andX-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-Identityheader 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
- Browser loads page, fetches
/wasm/qscs-substrate.wasm, instantiates it. - WASM either loads an existing wrapped blob from IndexedDB or calls
qscs_identity_generateto create one. - User submits the login form. The POST to
/auth/loginis signed; the body carriesusername,password,client_uuid, andpubkey. - QSCSCore verifies the signature against the supplied pubkey (proof of possession), then forwards the credentials to the control plane for validation.
- 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. - 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
| Condition | HTTP status | Response body |
|---|---|---|
| Missing or malformed signature headers | 401 | {"error":"identity signature required"} |
| Timestamp outside ±60 s window | 401 | {"error":"identity signature required"} |
| Nonce already seen for this UUID | 401 | {"error":"identity signature required"} |
| Signature does not verify against stored pubkey | 401 | {"error":"identity signature required"} |
| Client UUID unknown to this node | 401 | {"error":"identity signature required"} |
All failure paths emit an identical client-visible message; the discriminating reason is logged server-side only.
Related
- HTTP API: Signed Request Format, full wire details, header reference, and curl examples.
- Security Model, threat model context.
- WASM Module Specification, substrate runtime overview.