Browser and SDK Usage
Build browser WebTTY clients and decrypt recordings with the JS SDK.
Browser WebTTY integrations use the JS SDK. This is the same surface used by the product terminal and by custom web applications that need to open a WebTTY session from a browser.
A browser does not hold durable rstream credentials. The backend resolves the selected server, checks permissions, mints a short-lived token or session grant, and returns only the connection information needed by that browser session.
Browser integrations keep authorization and rendering separate. The backend resolves and authorizes; the browser renders the terminal and performs local crypto when needed.
browser UI
|
| asks application backend for a WebTTY session
v
application backend
|
| checks rstream permissions and resolves server
v
rstream Control plane / engine
|
| short-lived connection envelope
v
browser WebTTY clientKeep this split even for custom integrations. The browser renders the terminal and performs local crypto when needed. The backend owns authorization, server resolution, token minting, and policy checks.
The browser client supports the FIPS-compatible P-256 suite over WebTransport. Browser WebCrypto is outside the Go Cryptographic Module boundary; filesystem sharing remains outside the restricted profile. See the FIPS compatibility matrix.
Open a browser terminal
For a published WebTTY endpoint, resolve the advertised transport and pass it to the browser client with a short-lived token:
import { WebTTY } from "@rstreamlabs/webtty";
import { resolveWebTTYBrowserEndpoint } from "@rstreamlabs/tunnels";
import type { WebTTYServer } from "@rstreamlabs/tunnels";
function connectTerminal(server: WebTTYServer, token: string) {
const endpoint = resolveWebTTYBrowserEndpoint(server);
const url = new URL(endpoint.url);
url.searchParams.set("rstream.token", token);
const terminal = new WebTTY({
url: url.toString(),
transport: endpoint.transport,
});
terminal.connect();
return terminal;
}Use short-lived tokens scoped to the selected tunnel or registered server. Do not put personal access tokens, application secrets, or long-lived credentials in browser URLs.
Resolve registered servers server-side
For registered servers, the backend resolves the server and enforces product policy before the browser receives connection data. The browser does not need to know whether the backing server is a lightweight WebTTY tunnel, a registered server, or a workspace-managed E2E server. It receives a session-specific connection envelope.
When the server requires E2E, the browser must also be a trusted workspace browser or receive explicit-key material through an application-specific trust flow. Otherwise the session fails before terminal content is sent.
WebTTY E2E helpers
The SDK exposes payload crypto primitives for integrations that own the trust decision directly:
import { createWebTTYE2EClientPayloadCrypto } from "@rstreamlabs/webtty";
import { generateWebTTYE2EIdentity } from "@rstreamlabs/webtty";Use explicit-key crypto when the integration owns recipient selection. Use workspace-managed crypto when the browser is a trusted workspace browser and the registered server has a workspace-managed encryption policy.
Do not reimplement key id derivation, HPKE key wrapping, or AES-GCM payload encryption in application code. Use the SDK helpers so browser clients, CLI clients, and recording replay use the same crypto behavior.
Recording replay
The JS SDK also exposes text rendering and encrypted recording replay helpers:
import { createWebTTYE2EReplayPayloadCryptoFromKeyGrant } from "@rstreamlabs/webtty";
import { decryptWebTTYRecordedTextLog } from "@rstreamlabs/webtty";
import { renderWebTTYRecordedTextLog } from "@rstreamlabs/webtty";Use renderWebTTYRecordedTextLog for plaintext recordings. Use createWebTTYE2EReplayPayloadCryptoFromKeyGrant and decryptWebTTYRecordedTextLog for encrypted recordings after the backend returns authorized decrypt material and the browser has the matching trusted private key.
The replay helpers intentionally implement terminal-scrollback behavior. Alternate-screen applications are excluded from text export after they exit and restore the main screen, while the active alternate-screen snapshot can be included if export happens during the alternate-screen state.
Filesystem sidecar
The filesystem sidecar is a separate file API next to the terminal. It can expose directory listing, file read, upload, download, and write operations under a configured root, and it is separate from terminal payload encryption. Browser integrations do not expose the sidecar when the WebTTY session requires E2E terminal content.
If a browser workflow needs file access next to an encrypted terminal, design that file surface with its own explicit authorization and encryption model. Do not rely on WebTTY terminal E2E to protect a separate filesystem path. WebTTYFileSystem shares RemoteFileSystem with the standalone file browser and discovers WebDAV or WebRTC automatically. WebRTC is read-only and uses the project’s STUN/TURN configuration; writes fail explicitly.
Transport compatibility
Go and C++ servers advertise rstream.webtty.transport, exposed as transport in the parsed inventory. Preserve the resolved transport when opening another tab, reconnecting, or opening fullscreen. Unknown or conflicting metadata is an error. Legacy WebTTY datagram metadata can identify WebTransport; other unlabeled servers retain the historical WebSocket default.
A browser connects to a WebSocket or WebTransport endpoint matching that server. If WebTransport is unavailable in the browser, report that capability error; retrying the same server as WebSocket cannot repair it. A browser cannot open a native plain endpoint or private rstrm:// dial. C++ servers support plain and websocket; WebTransport servers are implemented in Go.
Node integrations using WebSocket should pass the SDK's per-client Node factory:
import { WebTTY } from "@rstreamlabs/webtty";
import { nodeWebSocketFactory } from "@rstreamlabs/webtty/node";
const terminal = new WebTTY({
url: "wss://example.rstream.dev/webtty?rstream.token=<short-lived-token>",
transport: "websocket",
webSocketFactory: nodeWebSocketFactory,
});This factory bounds connection setup, payload size and shutdown without replacing the global WebSocket constructor. The hosted MCP currently supports WebSocket and reports unsupported WebTransport before opening a terminal session.