secure-channel
An experimental TypeScript client and server binder for request/response messages over mutual TLS WebSockets. This package does not provide certificate issuance, service authorization or a gateway.
Install and verify
Section titled “Install and verify”npm install @localzet/secure-channel# From this repository (Node.js 22+, OpenSSL required for tests):npm cinpm testClient
Section titled “Client”import { readFileSync } from 'node:fs'import { SecureChannelClient } from '@localzet/secure-channel'
const client = new SecureChannelClient({ url: 'wss://gateway.example.com', serviceId: 'billing', certificate: readFileSync(process.env.CLIENT_CERT!, 'utf8'), privateKey: readFileSync(process.env.CLIENT_KEY!, 'utf8'), caCertificate: readFileSync(process.env.CHANNEL_CA!, 'utf8'),})await client.connect()try { const payload = await client.request({ route: 'health', payload: {} }) console.log(payload)} finally { client.disconnect()}request() resolves the response payload and rejects on timeout, disconnection or a server error. Concurrent connect() calls share one connection attempt. Unexpected closure schedules reconnection; explicit disconnect() cancels it and rejects outstanding requests. A request can have succeeded remotely even if its response was lost: retrying non-idempotent operations requires application-level idempotency keys.
Only https: and wss: URLs are accepted. Server certificate verification is always enabled; omitted caCertificate uses Node.js’s trusted CAs. This corrects earlier behavior that disabled certificate verification when CA was omitted. Timestamp and nonce headers are generated by the client and cannot be overridden through request headers.
Server
Section titled “Server”Create an HTTPS server with requestCert: true, rejectUnauthorized: true and trusted client CAs. Attach a WebSocketServer with an explicit maxPayload, then call bindSecureChannelServer({ wss, verifyClient, onRequest }). The binder rejects sockets without an authorized TLS client certificate. verifyClient should additionally enforce allowed service identities; trusting a CA alone is not service authorization. Handler exceptions return a generic error without exposing internal messages.
Replay protection rejects reused nonces, stale timestamps and requests when its bounded cache is full. Defaults: 30 s clock skew, 60 s nonce TTL, 10,000 entries. TTL must be at least twice the clock skew. Cache scope is one binder in one process: replicas need shared replay protection or separate certificate/connection routing. Configure ingress connection, message and request-rate limits; the binder does not implement them. Message payloads remain application-defined and must be validated by handlers.
Development
Section titled “Development”npm test builds the package and runs network tests with ephemeral certificates generated outside the repository. npm run build produces dist/. No registry release is performed by CI. Breaking security corrections should be reviewed by consumers before upgrading.
Source · AGPL-3.0