Skip to main content
The Flow Agent dashboard is a thin browser client over the read-only trace API the oracle exposes at /flow-agent/traces/*. It gives fleet-wide visibility across every flow room your oracle is running and lets you drill into any single run down to its span waterfall. Use it when you need to:
  • Watch throughput and flow health across the fleet in real time.
  • Inspect the run history and recent errors for a specific flow.
  • Trace a single tick — command counts, span durations, status snapshots — to debug a stuck or misbehaving flow.
Access is limited to the operator DIDs you allowlist on the oracle — a non-listed account is rejected at UCAN delegation time, before any dashboard data is returned.

Sign in with ImpactsX

The dashboard has a single sign-in front door: Sign in with ImpactsX, backed by the WorkOS-based ixo Auth Hub. The flow is:
1

Click Sign in with ImpactsX

The dashboard generates a CSRF state value, stashes it in sessionStorage, and redirects the browser to ${AUTH_HUB_URL}/api/auth/login?redirect_uri=${origin}/auth/callback&state=….
2

Authenticate at the Auth Hub

The Auth Hub authenticates the operator (via WorkOS) and redirects back to ${origin}/auth/callback with a single-use code (~120s TTL) and the state echoed back for verification.
3

Exchange the code for a session

On /auth/callback, the dashboard verifies state, then calls ${AUTH_HUB_URL}/api/auth/exchange?code=…. The Auth Hub returns the operator’s did and their Ed25519 signing mnemonic. The code is single-use — the callback route is guarded against React’s double-invoke so the exchange runs exactly once.
4

Mint a UCAN invocation and get a session token

The dashboard mints a UCAN invocation of the oracle’s pre-issued flow/observe delegation and POSTs it to /flow-agent/auth/session as Authorization: Bearer <invocation>. The oracle verifies the invocation chain back to its root key and, if the invoker is in the operator allowlist, returns a short-lived HMAC session token.
There is no PIN prompt, no Matrix vault read, and no QR or WebAuthn step. The Auth Hub returns the operator’s signing key directly, so the whole exchange finishes in one round trip.

Configure the Auth Hub URL

The dashboard picks the Auth Hub URL from the chain network by default: To point at a local Auth Hub during development, set VITE_AUTH_HUB_URL on the dashboard — it overrides the network-derived default:
Whatever origin serves the dashboard must be registered as a valid redirect_uri on the Auth Hub, since the callback URL is ${window.location.origin}/auth/callback.

Session contract

The oracle exposes three routes under /flow-agent/auth. All of them are excluded from the runtime auth middleware — the FlowDashboardAuthGuard is the sole authority for the trace API.

POST /flow-agent/auth/session

Send the one-time UCAN invocation as a Bearer credential:
Response body:
The session token is a compact HMAC (base64url(body).base64url(sig)) signed with FLOW_DASHBOARD_SESSION_SECRET. It is stateless — the oracle keeps no session store — and short-lived (sessionTtlMs, default 15 minutes). The dashboard stores the token in localStorage under fa_session and attaches it to every subsequent request as Authorization: Bearer <token>.
Requests carry the token in a header, not a cookie. That means the browser never sends credentials cross-origin, so the oracle can serve every dashboard origin under a wildcard Access-Control-Allow-Origin — a single oracle can back many dashboard deployments. This is the reason the old fa_session httpOnly cookie was replaced.

GET /flow-agent/auth/session

Returns { "did": "…" } when the token is valid, 401 otherwise.

POST /flow-agent/auth/logout

Returns { "ok": true }. The token is stateless, so logout is a client-side concern — the dashboard clears its localStorage entry. The endpoint is kept for symmetry and future revocation.

Configure the oracle

The oracle side reads its configuration from process.env. The relevant vars:
FLOW_DASHBOARD_COOKIE has been removed and the service getter cookieTtlMs has been renamed to sessionTtlMs. If you were reading either name, update your callers. The env var name for the TTL itself is unchanged.

Dashboard security headers

The deployed dashboard ships a strict Content-Security-Policy plus companion headers. On Vercel these come from apps/flow-dashboard/vercel.json; the same CSP is applied to vite preview from apps/flow-dashboard/vite.config.ts so violations surface locally too.
Why these settings:
  • script-src 'self' is the XSS guard for the session token, which is now readable to JavaScript (it lives in localStorage rather than an httpOnly cookie).
  • 'wasm-unsafe-eval' is required because @cosmjs/crypto instantiates libsodium as inline WebAssembly to sign the UCAN invocation. It permits WebAssembly instantiation only — JavaScript eval() stays blocked.
  • connect-src allow-lists *.ixo.earth (HTTP + WSS) so the dashboard can reach the oracle API and the Auth Hub. If your oracle API is served from a different domain, extend connect-src in both vercel.json and vite.config.ts.
  • frame-ancestors 'none' + X-Frame-Options: DENY prevent the dashboard from being framed (clickjacking).

Local development

Run the dashboard against a locally-running oracle:
The Vite dev server proxies /api/* to the oracle so the dashboard runs same-origin. Auth still rides a Bearer token — the proxy just spares you from configuring CORS locally. To open the trace API without any sign-in (no wallet, no operator DID), set FLOW_DASHBOARD_AUTH_DISABLED=true on the oracle. Do not do this in production.

Observability

LangSmith tracing, plugin status events, and the runtime logger.

Identity and auth

UCAN delegations, operator identity, and the auth surfaces the runtime exposes.

Deployment

Ship the oracle and the dashboard to production.

Environment variables

Every env var the runtime declares.