Skip to main content
Reference

Security

Backend-first auth and access control patterns.

As covered in Orchestration Architecture, run the Sandbox Agent client on your backend, not in the browser.

This keeps sandbox credentials private and gives you one place for authz, rate limiting, and audit logging.

Auth model

Implement auth however it fits your stack (sessions, JWT, API keys, etc.), but enforce it before any sandbox-bound request.

Minimum checks:

  • Authenticate the caller.
  • Authorize access to the target workspace/sandbox/session.
  • Apply request rate limits and request logging.

Examples

Rivet

Use onBeforeConnect, connection params, and actor keys together so each actor enforces auth per workspace.

Hono

import { Hono } from "hono";
import { bearerAuth } from "hono/bearer-auth";

const app = new Hono();

app.use("/sandbox/*", bearerAuth({ token: process.env.APP_API_TOKEN! }));

app.all("/sandbox/*", async (c) => {
  const incoming = new URL(c.req.url);
  const upstreamUrl = new URL(process.env.SANDBOX_URL!);
  upstreamUrl.pathname = incoming.pathname.replace(/^\/sandbox/, "/v1");
  upstreamUrl.search = incoming.search;

  const headers = new Headers();
  headers.set("authorization", `Bearer ${process.env.SANDBOX_TOKEN ?? ""}`);

  const accept = c.req.header("accept");
  if (accept) headers.set("accept", accept);

  const contentType = c.req.header("content-type");
  if (contentType) headers.set("content-type", contentType);

  const body =
    c.req.method === "POST" || c.req.method === "PUT" || c.req.method === "PATCH"
      ? await c.req.text()
      : undefined;

  const upstream = await fetch(upstreamUrl, {
    method: c.req.method,
    headers,
    body,
  });

  return new Response(upstream.body, {
    status: upstream.status,
    headers: upstream.headers,
  });
});