Documentation

Architecture & sessions

What actually happens between a technician clicking Connect and controlling a machine.

Three parties: the Agent (technician), the Relay (your server) and the Client (the supported machine). Both endpoints dial out to the relay over WSS, so neither needs a public IP or an inbound firewall rule, and the relay matches them by session id.

   AGENT (technician)                RELAY (your host)              CLIENT (supported machine)
   ┌────────────────────┐  WSS /agent  ┌────────────────────┐  /client WSS  ┌──────────────────────┐
   │ browser console     │◄───────────►│ pairs by sessionId, │◄────────────►│ portable exe          │
   │ or native console   │             │ forwards opaque bytes│              │ or installed service  │
   └────────────────────┘             └────────────────────┘              │  + backstage (SYSTEM) │
        views + controls                    dumb pipe                       └──────────────────────┘

Why the relay is deliberately dumb

The relay pairs two sockets presenting the same session id and forwards frames between them without interpreting the payload. Keeping it that way limits what it can see, keeps it out of the cardholder-data path for a PCI assessment, and left room to add end-to-end encryption without touching the relay at all — which is exactly what happened.

The one message the relay originates rather than forwards is peer state: each endpoint is told when its partner is waiting, paired or gone, so neither side wastes bandwidth encoding frames nobody is receiving.

A session, step by step

  1. Create. A technician signs in to the portal and creates a one-time session — a label, an expiry, single-use or reusable. That yields a join link and an "open console" link, and the list shows live status: waiting → connected → used.
  2. Join. The user opens the link and gets a one-click launcher (a small script that runs the portable client with the right relay, session and token) plus the equivalent command for anyone who would rather see it. Alternatively they open your portal's front page and type the code. Enrolled devices skip this entirely.
  3. Authorize. The relay validates the session id against the portal's registry — format, token, expiry, single-use — with constant-time comparisons. A one-time link is consumed once its client session ends.
  4. Pair and key. Once both sides are present they run an ECDH exchange through the relay and derive their own AES-256-GCM keys. See the security model.
  5. Work. Frames flow Client → Agent; input flows Agent → Client. Files, clipboard, voice and the backstage shell share the same channel.

Capture and encoding

The client grabs the screen with GDI BitBlt by default — it works everywhere, including from a service — with DXGI Desktop Duplication as a faster path where it initializes. Each frame is split into 128×128 tiles, and only the tiles that changed since the previous frame are encoded and sent as a delta. A full key frame is forced every 120 frames so an Agent that joined late or dropped a packet resynchronizes on its own. JPEG quality defaults to 70 and is configurable on the capturing side; an H.264 encoder is also present for deployments where it is a better fit.

The Agent paints tiles onto a canvas, aspect-fit to the window. Because only changed tiles move, a mostly-static desktop costs very little bandwidth — and a full-screen video costs a lot. That is the tradeoff the tile encoder makes.

Input

Mouse and keyboard coordinates are normalized to 0–65535 over the client's screen, so they are independent of either side's resolution and map directly onto the Windows absolute coordinate space. Keys travel as Windows virtual-key codes; the browser console maps KeyboardEvent.code to a VK before sending.

Desktop versus backstage

Mode is not a relay concept — the relay only pairs by session id. The two modes are separated by a derived id: for a support code S, desktop control uses S and the backstage SYSTEM shell uses S-bs. The Agent appends the suffix when the technician picks Backstage; an installed client listens on both. The user only ever sees and shares S.

Keep S at 61 characters or fewer so S-bs still fits the relay's 64-character session id limit. The portal's generated codes already respect this; it only matters if you are minting ids yourself.

File transfer

Either side can push a file: an open message with name and size, then 64 KB chunks respecting WebSocket backpressure, then a close carrying the SHA-256 of the whole file. The receiver verifies that hash before acknowledging. The native client reads and writes under configured inbox and outbox directories; the browser console downloads what it receives.

The portal's data model

ThingWhat it is for
UsersTechnicians, with a role of admin, operator or viewer.
CustomersGroups devices, so an MSP technician works within one client at a time.
DevicesEnrolled installed clients, each with its own device token and live presence.
SessionsOne-time or reusable support sessions with expiry and live status.
RequestsAd-hoc access requests raised from the join page, for a technician to accept.
AuditAdministrative and session events, for export to your own logging.

Known limits

  • The Windows secure desktop — UAC prompts and Ctrl-Alt-Del — is not captured. Sign-in and lock screens are.
  • Endpoints are Windows only. The technician console is cross-platform because it is a browser page.
  • The tile codec is efficient for typical desktop work, not for full-motion video.