Skip to main content

What event streaming is

Event streaming gives you a persistent, real-time connection to theAuth events via Server-Sent Events (SSE). Whenever your code calls stream.emit() (an agent is revoked, a budget is exceeded, and so on), connected clients receive it, no polling required. Events are also persisted to the database so you can replay anything you missed.

Streaming vs webhooks

Webhooks and SSE are separate mechanisms with separate event sets: the webhook module delivers the events you pass to theauth.webhooks.emit(), and the stream delivers the events you pass to stream.emit(). You can emit the same occurrence to both. Use webhooks when you need durable delivery to an external service. Use event streaming when you need a live view, a security dashboard, an admin feed, or a CI script watching for budget.exceeded.

Setup

handleRequest takes a Web Request and returns a Web Response, or null for any request that is not an SSE request: the method must be GET, the path must end in /events/stream, and the Accept header must include text/event-stream. This makes it safe to call inside a catch-all handler. Node (req, res) handlers such as Express need a small adapter to convert to and from Request and Response.

Connecting from a browser

The browser’s built-in EventSource API handles reconnection automatically.
If you pass the token via the Authorization header instead, use the eventsource package or a fetch-based polyfill, since the native EventSource does not support custom headers.

Connecting from Node.js

Event types

The stream module is standalone. The theAuth core does not call stream.emit() for you, so none of these events fire automatically: you emit the ones you need from your own code, hooks, or webhook handlers. anomaly.detected is only a reserved type name, since theAuth has no anomaly detector.
The type column below describes the intended meaning of each type.

Filtering events

Pass a types query parameter with a comma-separated list to receive only the events you care about.
Unknown type names in types are ignored; if none are valid, the connection receives all types. You can also restrict the types at the module level, which filters live delivery.

Replay and cursor

Events passed to emit() are persisted in the theauth_stream_events table (a failed write is ignored). If a client disconnects and reconnects, pass since to receive everything it missed, oldest first, after the connected event. since must be an ISO 8601 timestamp with an offset or Z; anything else is rejected with a 400.
The module also reads the Last-Event-ID header as a fallback cursor, but it parses the value as a date. Each SSE message uses your event id as its id: field, so the header only works for replay if your event IDs are timestamps (for example ISO strings). With UUID IDs, as in the examples here, an automatic browser reconnect replays nothing, so track the last timestamp yourself and pass since. Replay applies the connection’s types filter, or the module-level eventTypes if the client sent none. A client that passes its own types can replay types outside the module-level list, and the programmatic replay() method does not apply the module-level list at all.
replay returns up to 1000 events in descending order (newest first). Apply your own pagination on top if you need to page through large windows.

Auth requirements

By default requireAuth: true. Every connection must present a Bearer token, either in the Authorization header or as the token query parameter.
When the token is missing or validateToken returns null, the stream sends a single error event and closes (the HTTP status is still 200).
If you set requireAuth: true but do not provide validateToken, any non-empty token is accepted. Always supply validateToken in production.
To disable auth for local development or internal-only deployments:
Never disable auth in production. The stream exposes audit events and agent lifecycle data.

Configuration

Connection limits

The stream rejects connections beyond maxConnections with a 503 Too many connections response. Size this based on your deployment: a single process can comfortably handle hundreds of concurrent SSE connections; above that, consider a pub/sub layer (Redis, NATS) in front of the module.

Heartbeat

The server sends : heartbeat comments on the configured interval (default 30 seconds) to keep load balancers and proxies from closing idle connections. No action is required on the client side, EventSource ignores comment lines.

Emitting events from plugins

Any part of your application can emit to the stream.
Integrate with the webhooks module to fire both a webhook and a stream event from the same action.

Module API

Webhooks

Durable HTTP delivery for the same events to external services.

Audit trail

The audit log. Replay reads from the separate stream events table, not from audit entries.

Hooks

Call stream.emit() from lifecycle hooks such as onViolation and onAgentRevoke.

Dashboard

Visual monitoring of agents and audit entries.
Last modified on October 7, 2026