Security
Introduction
Section titled “Introduction”Any local process and any web page can reach a localhost port. The local backend therefore refuses by default and asks you to write down two decisions: how the agent executes, and which pages may talk to it. Every request also needs a per-launch token.
Choosing the execution mode
Section titled “Choosing the execution mode”await startLocalServer({ // ... execution: 'local-unsandboxed',});execution: 'local-unsandboxed' runs the agent’s execute tool as a shell on this machine, with the current user’s permissions and environment. The package will not start without the choice written down, so nobody gets it by omission. A sandboxed backend is a later phase.
@pilotoo/agent-runtime takes the same choice (createAgentBackend(..., { execution })) and throws on a value it cannot serve instead of falling back to the shell. The shared gateway, which leaves it out, is unchanged.
Allowing your page’s origin
Section titled “Allowing your page’s origin”allowedOrigins is required. The desktop launcher passes the webview origins, plus the dev server’s origins in development.
await startLocalServer({ // ... allowedOrigins: ['tauri://localhost'],});A request with an Origin outside the list is refused (403 on REST, no socket), token or not. An empty list refuses every request that carries one. A request with no Origin is judged by the token alone.
| Page | Origin it sends |
|---|---|
| Tauri webview on macOS or Linux | tauri://localhost |
| Tauri webview on Windows | http://tauri.localhost or https://tauri.localhost |
| A dev server | its own origin |
Sending the token
Section titled “Sending the token”Every request needs Authorization: Bearer <token>:
- REST goes through the identity guard and answers 401 without it.
- Sockets go through the same resolver in the handshake and fail with
connect_errorUNIDENTIFIED.
Both sides are hashed and compared in constant time. The caller is the fixed local identity: subject: local, tenant: local, roles: [owner]. /health and /protocol stay open, though they are still origin-checked.
The client needs nothing special: pass the base URL and credentials: () => token to chat-core (see Connecting a client).
Next steps
Section titled “Next steps”- Local backend for the full option list.
- Hosting it from another app for how the token reaches the page.