NodeForEdge

Documentation / PhoneGate

Security model

Why PhoneGate uses separate secrets for the browser, the phone and AI clients, and which rules are enforced at the web edge.

PhoneGate controls a real phone number, so its trust boundaries are explicit. The rule behind all of them: a secret that lives on a device an attacker might hold must not unlock anything more than that device needs.

Three secrets, three jobs

Secret Protects Where it lives
Admin token Browser session, the whole REST API, the update control plane Server only, in an ignored environment file
Device token The device WebSocket and the signature of update packages Server and the rooted phone
MCP access token The /mcp endpoint for remote AI clients Server and the client's secret store

The three values must differ. The device token sits on a phone, and a phone can be lost or rooted by someone else. If it equalled the admin token, one secret taken from the handset would open the entire API.

An empty device token silently falls back to the admin token. That is kept only for legacy installs and is not a supported configuration.

Browser sessions

The browser signs in once with the admin token and receives an HttpOnly, SameSite session cookie. The token is never kept in localStorage, so a script injected into the page cannot read it.

Rules at the web edge

Caddy enforces some rules before the application sees a request:

  • Updates are tailnet only. Everything under the update path is accepted only from the private tailnet range or from the server itself. Any other source gets 403 before the application checks a token.
  • MCP needs a bearer token. Requests to /mcp without the correct Authorization header get 401 plus metadata that lets an OAuth-capable client find the sign-in flow.
  • OAuth discovery stays public. The well-known and OAuth paths are served by the unified OAuth gateway so that clients can authenticate.

Signed updates

New daemon builds reach the phone as signed over-the-air packages. The signature uses an HMAC keyed by the device token. The control plane that triggers an update is administrative and, on top of that, restricted to the tailnet.

Rotating the device token

Rotation is a script, not a manual edit. It refuses to run during an active call, verifies the hash of the token on the device before replacing it, briefly lifts the immutable flag on the environment file, and waits until the daemon has reconnected after the service restarts. A call in progress is never cut.

Secrets in practice

  • Secrets are only ever stored in ignored environment files and on the device in a file readable by its owner.
  • Optional provider keys, such as speech-to-text keys, follow the same rule.
  • No secret is placed in an MCP client configuration; the MCP process reads its own from the server environment.

Built 2026-10-06. Addresses, tokens and ports are left out on purpose.