Skip to main content
The worker-manager worker owns the connections between workers and the engine. It always runs a trusted listener (on 49134 by default) that your own workers connect to through III_URL. To let an untrusted client connect, a browser tab, a third-party process, anything you do not run yourself, you add an RBAC-gated listener: a second port where every connection is authenticated by a function you write and every call is checked against an allowlist.
worker-manager is always running, so there is nothing to add; you configure it directly in config.yaml. This page is a quick tour of RBAC listeners. For the full configuration see the worker-manager worker docs.

Trusted and RBAC listeners

The default 49134 listener is trusted: any worker that reaches it can register functions and call anything. That is fine for workers you run yourself, but not for a browser or other untrusted worker. An RBAC listener runs on its own port, gates every connection through an auth function, and restricts each session to an allowlist of functions.
Declaring any worker-manager in config.yaml replaces the default 49134 trusted listener. You must also declare the trusted 49134 listener yourself alongside the RBAC one, otherwise your own workers lose the port they connect through.
Declare both listeners: the trusted one your own workers keep using on 49134, and an RBAC-gated one on a separate port (here 3110, for browsers and other untrusted connections):
config.yaml
auth_function_id names a function the worker invokes once per connection to authorize the worker to connect (or reject it if authorization fails). That is covered in the next section. expose_functions is the allowlist of function IDs a session may call. Each entry is either a glob match("...") on the function ID or a metadata: selector that matches any function registered with that metadata:
A function’s metadata is an arbitrary JSON object set when the function is registered, so you can shape it however your access model needs and gate on exactly the fields you choose, for example { public: true }, { tier: "premium" }, or { scopes: ["read"] }.
All access should be gated system-side. You should never rely on an untrusted worker to define what they can or can’t have access to. For example metadata.public = true in the above example is defined and managed by the trusted worker-manager and is not part of a payload sent by the worker.

Write the auth function

The auth function runs during the WebSocket upgrade, before the client is connected. It receives the request’s headers, query parameters, and client IP, and returns the session’s permissions. Throw to reject the connection.
The auth function can grant multiple authorizations so a single function can be used to authorize multiple types of workers. In practice this is a balance between authorizing similar workers and separating dissimilar workers to separate worker-manager definitions. You can define any number of worker-managers in iii’s configuration.
src/index.ts
The auth worker itself connects to the trusted 49134 port; it is one of your own workers. Only the untrusted client connects through 3110. The returned object is an AuthResult:

Connect a client

A browser connects with iii-browser-sdk pointed at the RBAC port. Browsers cannot set custom WebSocket headers, so the token travels as a query parameter, the same one auth::browser reads:
src/iii.ts
The session can now call only the functions expose_functions (plus allowed_functions) permit. For an end-to-end walkthrough that turns a browser tab into a worker, see Ch. 7: Bring in the browser.

Intercept calls with middleware

Set middleware_function_id on the listener to run a function on every invocation that comes through the RBAC port. It receives the call plus the session context from the auth result, and acts as a proxy: forward the (optionally rewritten) call and return its result, or throw to reject.
config.yaml
src/index.ts
The rbac block also accepts on_function_registration_function_id, on_trigger_registration_function_id, and on_trigger_type_registration_function_id hooks. Each runs when an untrusted session registers a function, trigger, or trigger type, and can remap the registration (return the mapped fields) or throw to deny it.