Remote access
Each machine runs its own Overdeck. That machine owns its projects, agents, conversations, terminals and credentials, and its dashboard serves only its own state. Another device (a laptop, a tablet, a second desktop) reaches a machine by pairing with it. Pairing gives that device its own revocable session. The machine’s root internal token never leaves the machine.Pairing from the terminal (
pan pair, pan devices) is in v0.64.0. Settings → Anywhere,
Settings → Access Tokens and scoped API tokens (pan token) arrive in the next release
(v0.65.0).GET /api/environment returns it
without a credential:
Pair a device
From the dashboard
- On the machine, open Settings → Anywhere and click Pair a device.
- Pick the address the other device opens, for example your Tailscale name. If it is not in the list, choose Another address…, type it, and click Add to trusted addresses. It is trusted at once, with no restart. Use this machine only makes a link that works only on this machine.
- Click Create pairing link. Scan the QR code with the other device, or copy the link and open it there. The dialog names the device when it pairs.
From the terminal
-
On the machine, run
pan pairwith an address the other device can reach:It prints a URL such ashttps://desk.tailnet.ts.net/#pair=odp_…, the expiry time, and the raw credential for manual entry. Use--jsonfor{ url, credential, expiresAt }.--label <name>records a name for the pairing in the activity log. - Open that URL on the other device. The dashboard exchanges the credential for a device session, removes it from the address bar, and loads.
- works once, and expires 10 minutes after it was created;
- lives only in the running dashboard’s memory, so a dashboard restart invalidates every credential that has not been used yet;
- always travels in the URL fragment (
#pair=), never in a query string, so it never reaches a server or proxy log.
--url, pan pair uses this machine’s own dashboard address. When
that address is localhost (or 127.0.0.1, ::1, *.localhost), the URL only
works on this machine, and pan pair says so.
pan pair talks to a dashboard started by pan up, which shares this
machine’s internal token. A paired device cannot create more pairing
credentials.
Open one conversation on another screen
To look at one conversation on your phone or another computer while this machine keeps running it, open the conversation’s ⋮ menu (in its header or on its row) and choose Continue on another device. The Open on another screen tab shows a link to that conversation, a Copy button and a QR code. The tab offers only trusted addresses other devices can reach, never a loopback address. If there is none yet, type one and click Add an address. In a browser on this machine, Also pair the device is checked by default. Click Create pairing link to add a one-time pairing credential to the link (…/conv/<id>#pair=odp_…): an unpaired device that opens it pairs and lands on
the conversation in one step. The credential follows the same rules as above:
it works once, expires after 10 minutes, and travels only in the URL fragment.
On a paired device the option is not shown, and the link works for devices
that are already paired. Available since v0.65.0.
Open the dashboard at a non-default address
The dashboard only accepts browser requests from origins it trusts. To open it at an address other than the default (for example through Tailscale), add that address in the pair dialog with Add to trusted addresses. It takes effect on the next request, with no restart, and is stored in~/.overdeck/trusted-origins.json:
localhost, 127.0.0.1, ::1, *.localhost) cannot be
added: they are already trusted for this port and never help another device.
To remove an address, edit the file and restart the dashboard.
OVERDECK_TRUSTED_ORIGINS still works and is merged with the file. Separate
several origins with commas, and set it before starting the dashboard:
List and revoke devices
Settings → Anywhere lists paired devices with their scopes, when each was paired and when it was last seen. Revoke there has the same effect aspan devices revoke. From the terminal:
pan devices revoke writes the revocation straight into the registry; no
connections can be open then. The running dashboard also rereads the registry
every 5 seconds, so a revocation from any process takes effect within 5 seconds.
Device sessions are stored in ~/.overdeck/access-tokens.json (mode 0600).
The file keeps only a SHA-256 hash of each token. If the file is corrupt, the
dashboard accepts no device session and logs an error naming the file.
Anywhere status
The Anywhere card shows whether other devices can use this machine. It appears in Settings → Anywhere and on the Health page, and shows:- This machine: its label and the start of its environment id.
- Reachable at: the trusted addresses another device can open, or “Only this machine”.
- Paired devices: how many device sessions are active (not revoked).
- Session Vault: “Not set up”, “Locked on this machine”, “Key rotation
unfinished”, or “Ready” with its backend. Set up opens Settings → Session
Vault, which shows the
pan vault setup <git-url>command to run in a terminal. Setting up from the dashboard is planned (PAN-4446). Not using the vault is a valid choice, not a problem.
The card reads
GET /api/anywhere/status, which any dashboard credential may
call.
Scoped API tokens
A paired device can do everything the dashboard can. A program that needs only part of that (an event sidecar, Hermes, a script that sends messages to agents) should hold a scoped API token instead. A leaked scoped token exposes only the routes its scopes name, and it can never create a session, a pairing credential or another token. Create one on the machine:pan token create prints the token (odk_…) once. Store it right away; it
cannot be shown again. A running dashboard accepts a new token within 5 seconds.
The scopes:
Anything not in the table needs
admin. A request whose token lacks the scope
gets 403 with { "error": "insufficient_scope", "missingScope": "<scope>" }.
Send the token on every request as Authorization: Bearer odk_…. It works over
HTTP, the event stream and WebSocket upgrades. It does not work as a cookie or a
URL parameter, and a request carrying it needs no Origin header or CSRF token.
pan token revoke writes the revocation into the registry, and a dashboard that
starts later never accepts the token. Only this machine’s internal token or root
session can create or revoke tokens. The dashboard API is
GET/POST /api/access-tokens and DELETE /api/access-tokens/:id.
You can also manage tokens in Settings → Access Tokens: the table shows
each token’s name, scopes, created, last used and revoked times; Create
token shows the plaintext once with a Copy button; Revoke asks for
confirmation. A browser signed in as a paired device can see the list but
cannot create or revoke tokens; the section explains why.
What the LAN can reach
The dashboard binds every interface. Every/api/* and /events/* request that
does not come from this machine must carry a credential (the root session, a
device session, a scoped API token, or the internal token), or it gets 401.
A scoped token is always judged by its scopes, even from this machine. “From this machine”
means a loopback address, or the host-local Traefik and Docker networks that
front overdeck.localhost.
These routes answer without a credential:
GET /events/stream also accepts its OVERDECK_EVENTS_TOKEN bearer token when
that variable is set, so an external consumer such as a TTS sidecar keeps
working. A read:events scoped token works there too, set or not. The dashboard’s static page files stay public.
Local reverse proxies: require_token_mint
A local reverse proxy (Tailscale Serve, cloudflared, a Traefik route) connects
to the dashboard from 127.0.0.1, so every visitor looks like a local caller.
Turn on require_token_mint whenever such a proxy forwards outside traffic.
Idle dashboard terminals stay connected behind proxies with idle timeouts of 30s
or more because the terminal WebSocket exchanges a ping/pong control frame every
20s; programmatic clients opt in with ?heartbeat=1 (PAN-4434).
- A browser can only get a root session by presenting the internal token (for
example the one-time
#overdeck_token=<token>URL fragment, where the token is the contents of~/.overdeck/internal-token). Being local no longer counts. - A local request that carries a proxy header (
X-Forwarded-For,X-Forwarded-HostorForwarded) counts as remote, so it needs a credential.
#overdeck_token= fragment or pairing. You can also turn it on
in Settings → Access Tokens → Require a token to sign in. A Settings change
applies at once. A hand edit of config.yaml needs a dashboard restart. The key
is read only from the global ~/.overdeck/config.yaml, never from a project
.pan.yaml.
What pairing is not
- The relay is optional reachability. The Overdeck relay (PAN-2356) is one way to reach a machine. It is not where multi-machine state lives: each machine keeps its own.
- Moving a conversation to another machine is Session Vault. Pairing lets a device use a machine’s dashboard. To resume a conversation on a different machine, use Session Vault.