Relay API
@claxedo/workspace-relay is the single canonical tunnel process between
cloud-hosted browsers and workspace-runtime hosts, whether the host is a cloud
VM or a user laptop. One package, one process, one config surface.
Token model
Section titled “Token model”The relay verifies short-lived runtime access tokens, calls the configured target resolver / revocation callback, and forwards accepted traffic to the selected host with a freshly minted relay-host token.
| Token | Default TTL | Issuer | Audience | Purpose |
|---|---|---|---|---|
| Runtime Access Token (RAT) | 30 minutes | claxedo-control-plane | workspace-relay | User/browser authorization to reach one workspace and host through the relay. |
| Host Tunnel Token (HTT) | 5 minutes | claxedo-control-plane | workspace-relay-host-tunnel | Workspace runtime authorization to register a user-hosted tunnel. |
| Relay Host Token (RHT) | 60 seconds | workspace-relay | workspace-host-service | Per-request relay-to-host authorization minted after RAT validation. |
RATs and HTTs bind issuer, audience, subject, workspace id, host id, expiry,
issue time, and JTI. RATs also bind role. RHTs additionally bind the deployment
pair: cloud/cloud-vm or user-hosted/local-worktree.
Routes
Section titled “Routes”The relay has no /w/{workspaceId}/* URL prefix of its own — the gateway
pattern lives in claxedo-server. The relay is intentionally narrow: it handles
tunnel traffic and the auth checks that gate it.
| Route | Purpose | Auth |
|---|---|---|
| WS upgrade + tunnel framing | Host-tunnel registration and per-request forwarding | HTT (tunnel register) / RAT (per request), minted RHT to host |
GET /health | Liveness. Marked unhealthy during drain. | none |
GET /metrics | Privileged operational data (fragmentation, slow-consumer stats). | Authorization: Bearer <CLAXEDO_RELAY_METRICS_TOKEN>; when unset, loopback-only, fail-closed if no remote-address resolver |
Revocation and active checks
Section titled “Revocation and active checks”isRuntimeAccessTokenActive is the revocation/target freshness hook. Production
deployments should implement it by calling the control plane (or equivalent
authority) on every new HTTP request and WebSocket upgrade. A false result
rejects before forwarding.
Long-lived relayed sockets are authorized at establishment time. Already-open SSE, PTY, and WebSocket streams may live until normal close, reconnect, relay drain, host disconnect, or process restart. For immediate stream revocation the control plane must also close the session/runtime channel.
Forwarding boundary
Section titled “Forwarding boundary”The relay strips client-supplied x-forwarded-for, x-forwarded-host,
x-forwarded-proto, x-real-ip, x-claxedo-internal-*, and x-supervisor-*
headers. It replaces Authorization with an RHT, sets x-workspace-id, and
adds x-forwarded-by: workspace-relay.
For user-hosted targets, Cookie is stripped before forwarding — a user-hosted
workspace may run near a developer’s local browser cookie jar. Cloud VM targets
may receive cookies when the caller intentionally sends them.
Configuration
Section titled “Configuration”Local development needs none of these — the relay boots on loopback with an
ephemeral dev key. These knobs exist for production deployments, where exactly
four are required: CLAXEDO_RELAY_RESOLVER_URL, CLAXEDO_RELAY_RESOLVER_TOKEN,
one of CLAXEDO_CONTROL_PLANE_JWKS_URL |
CLAXEDO_RUNTIME_ACCESS_TOKEN_PUBLIC_KEY_PEM, and
CLAXEDO_RELAY_HOST_SIGNING_KEY_PEM. All knobs are environment variables, read
in packages/workspace-relay/src/main.ts (Bun process) and src/worker.ts
(Cloudflare Worker).
Required (production)
Section titled “Required (production)”| Env var | Purpose |
|---|---|
CLAXEDO_RELAY_RESOLVER_URL | Where to fetch RuntimeAccessTokenActiveResults (typically claxedo-server/internal/relay/target). Required on the Bun process. |
CLAXEDO_RELAY_RESOLVER_TOKEN | Bearer token the relay sends to the resolver. Required in production (fail-closed gate at src/main.ts). |
CLAXEDO_CONTROL_PLANE_JWKS_URL | Remote JWKS used to verify control-plane-issued tokens (RATs and HTTs). Takes precedence over the inline PEM. |
CLAXEDO_RUNTIME_ACCESS_TOKEN_PUBLIC_KEY_PEM | Inline public key for the same verification (alternative to JWKS). One of the two must be set. |
CLAXEDO_RELAY_HOST_SIGNING_KEY_PEM | Private PEM the relay uses to mint relay-host tokens (RHTs). Required in production — the relay refuses to start with an ephemeral key. |
Common
Section titled “Common”| Env var | Purpose |
|---|---|
CLAXEDO_WORKSPACE_RELAY_HOST | Listen hostname. Defaults to 127.0.0.1 (loopback). |
CLAXEDO_WORKSPACE_RELAY_PORT | Listen port. Defaults to 7777. |
CLAXEDO_RELAY_ALLOWED_ORIGINS | Comma-separated browser-origin allowlist for CORS. Replaces the built-in default list (Claxedo/OpenCode app origins plus http://localhost:* dev hosts). Grammar: exact origin, https://*.example.com, http://localhost:*. Works on both the Bun process and the Cloudflare Worker. |
CLAXEDO_RELAY_METRICS_TOKEN | Optional bearer token for /metrics. Without it, /metrics requires a trusted loopback remote-address resolver. |
NODE_ENV | production / development / test. Switches the production fail-closed gates (resolver token, RHT signing key). |
Cloudflare Worker (Durable Object deployment)
Section titled “Cloudflare Worker (Durable Object deployment)”| Env var | Purpose |
|---|---|
CLAXEDO_CENTRAL_URL | Worker-only fallback for the resolver base URL when CLAXEDO_RELAY_RESOLVER_URL is unset (one of the two is required). |
CLAXEDO_RELAY_LOCATION_HINT | Durable Object location hint for relay placement. |
CLAXEDO_APP_ORIGINS | Cloudflare-only, additive origin entries layered on top of the base allowlist (kept for existing deploys; prefer CLAXEDO_RELAY_ALLOWED_ORIGINS for full control). |
Additional knobs — RHT key-rotation extras (kid overrides, next-key
publication), cache TTLs, drain timeout, forwarding concurrency, synthetic-probe
and audit/trace sampling — exist with sensible defaults; see the package source
(packages/workspace-relay/src/main.ts, src/worker.ts) if you need them.
The relay owns CORS responses for browser-facing workspace requests. Do not
forward upstream CORS headers as the source of truth. Add allowed product
origins via CLAXEDO_RELAY_ALLOWED_ORIGINS and keep wildcard origins out of
credentialed deployments.
Pluggable token verification
Section titled “Pluggable token verification”Verification is pluggable via the RelayKey | RelayKeyResolver pair on
verifyRuntimeAccessToken and friends, and via the unified TokenVerifier
interface in @claxedo/workspace-relay-protocol. A custom verifier is only the
crypto/introspection authority; the relay still validates its output into
RuntimeAccessTokenClaims, binds the URL workspace id to the claims, applies
revocation, and allowlists roles. Missing, unknown, or malformed roles deny. Two
reference implementations ship in the protocol package:
createHttpTokenVerifier (remote/OIDC introspection) and
createStaticTokenVerifier (tests and single-tenant self-hosted setups).
For install instructions, architecture, and deployment shapes, see the workspace-relay package page.