The access token and who can reach the relay
A relay has one owner and one access token. Whoever holds the token has full control of the relay and, through its agents, of the user account the relay runs as. There are no user accounts, roles or per-device keys. This page says where the token comes from, how a browser or a script presents it, who can connect at all, what is reachable without it, and what to do if it leaks.
The token #
oar setup creates the token (a random one for a new config, 43 characters
of random letters, digits, - and _) and writes it to auth in the
config file, config. in OAR's state folder. The relay keeps that file
readable by you only, outside Windows. See
config.json and
Where secrets live.
Without an auth in the config, the relay makes a random token on every
start, prints it to its log and does not save it. Start the relay with
--token <value> and that token is used for the run only; it is never saved,
and it is part of the command line. Your agents read the token from
config. (see Agents and the token), so use a token that is
saved there if agents are to work.
oar url prints the address with the current token, for example
http://. Treat that address like a
password.
Ways to present it #
| Way | Used by |
|---|---|
The ?token= part of the page's address |
A browser, the first time. The page takes the token out of the address bar and sends it to the relay in a header; the relay answers with the sign-in cookie below. Added in 0.9.11 It works on the page address only: API, file and asset addresses do not accept a ?token= |
| The sign-in box, Enter your access token to connect, then Connect | A browser that has no cookie. A wrong token shows Invalid token; an empty box shows Please enter a token |
An Authorization: Bearer <token> header |
Scripts and API calls |
| The sign-in cookie | A browser that signed in before |
The token is never read from a request body or, since 0.9.11, from the query
of a request. If a request carries both a header and the cookie, the relay
uses the header. A wrong value is not skipped: a wrong header is refused even
when the cookie is right. The live connection (Socket.IO) reads the token from
the connection's auth. field or from the cookie, not from a header and
not from its query.
A token in the address
The first request for the page, /, carries the token in its
address. So the token can end up in the browser's history, in the logs of a
reverse proxy or tunnel in front of the relay, and in anything you copy the
address into. The page removes it from the address bar after loading and
signs in with a header, and no other request takes the token from the address.
Prefer the sign-in box or a header where you can.
Scripts that used ?token=
Up to 0.9.10 the relay accepted ?token= on every request. A script that
fetches API, file or asset addresses with it now gets 401: send
Authorization: Bearer <token> instead. A Socket.IO client passes the token
as auth.. See Upgrade notes.
The sign-in cookie #
After a valid token, the relay sets a cookie named copilot_ that lasts 30 days. This also
happens for a script that sends the token in a header. It is
HttpOnly, so page scripts cannot read it, and Same. It is marked
Secure when the relay is reached over HTTPS. If a request arrives with a
cookie that no longer matches the token, the relay answers 401 and clears the
cookie, and the browser shows the sign-in box. The cookie holds the token
itself.
Signing out and revoking a device #
The app has no sign-out button for the relay, and the relay keeps no list of signed-in devices. Because the cookie holds the token itself, one device cannot be revoked on its own. On your own browser, clear the cookie in the browser's site settings. To lock out every device, including one you lost, change the token (next section).
Rotating the token #
oar setup --new-token
This writes a new token and restarts the relay (in a terminal it asks first; see oar setup). What happens:
- Signed-in browsers. The old token stops working when the relay has
restarted. The restart drops the live connection, and the next request of each
browser fails: the relay clears its cookie and the browser shows the
sign-in box. Sign in again with the address from
oar urlor the new token. - Until the restart. If you decline the restart, the running relay keeps
accepting the old token until
oar restart. - Paired relays. A relay that has your token stored, because you paired the two, gets Token not accepted. Add the relay again there with the new token; see Remote relays. Removing a pairing on this relay does not revoke a token the other side already holds, so rotating is how you lock that relay out.
relay-. While a changed port or token waits for the restart,previous. json oar setupkeeps the old port and token in this file in the data folder (plain text, readable by you only), so thatoar status,oar stopandoar restartstill find the running relay. It is not a grace period: the file changes nothing about what the relay accepts, and theoarcommands delete it once the relay answers on the new settings. The old token stops working only when the relay restarts.- Share links and preview links have their own tokens and are not affected.
Editing auth in the file by hand works the same way; oar restart
applies it.
Who can connect at all #
localhost in the config decides where the relay listens:
localhost |
Setup option | The relay listens on | Reachable from |
|---|---|---|---|
true (the default) |
oar setup --local, or answer 1 |
127. |
This machine only |
| anything else | oar setup --lan, or answer 2 |
0. (all interfaces) |
Every device that can reach the machine's address and port |
Only the boolean true and the text "true" (any case) count as local.
false, null, 1, "yes" and every other value open the relay to the
network; the default applies only when the key is missing. oar setup writes
the key as true or false. A change needs oar restart.
oar setup, oar url and oar status read the key differently: only the
boolean false counts as LAN access for them, and oar doctor shows
localhost only for false. With a value such as null or "no"
the relay listens on all interfaces while those commands report this machine
only. Keep the key to true or false. See
config.json.
On a LAN, the token is the only gate: the relay does not check where a
request came from. With access this machine only, a phone cannot connect
until you switch on LAN access or use a tunnel. localhost does not
affect the managed tunnels, which connect outward from the machine.
A relay that sits behind a proxy or tunnel on the same machine can stay
this machine only. Which proxies' X- headers the relay
believes is set by trust (default loopback); that decides whether it
treats a connection as HTTPS and marks the cookie Secure.
What needs the token #
Everything that reads or changes your conversations, files, settings or agents needs the token. These are the exceptions, and the whole list.
| Path | Needs the token? | What it gives |
|---|---|---|
/ and / |
No | The web app and its sign-in box |
The web app's script, style and icon files, /, / |
No | The app itself, which holds none of your data |
/ |
No | The install manifest. It carries the app name you set in Settings |
/ |
No | The page of a shared conversation |
/ and its presence, upload and generated-image routes |
No, but a valid, unrevoked link token | Read-only access to that one conversation. See Sharing |
| Preview links on the preview host | No, but a valid preview token | The previewed app only; the preview host does not serve the relay. See Previews |
/ (all other routes) |
Yes | Conversations, settings, files, status, previews, pairing |
| The live connection (Socket.IO) | Yes, and Added in 0.9.11 a browser must open it from the relay's own address | The app's live updates. See allowed for a proxy that rewrites the host |
| The workers' connection to the relay | Yes | Used by your agents' own processes on this machine |
| Files from your drives and workspace, uploads and generated images by their own address | Yes | A shared viewer cannot load them this way; the shared routes above serve the ones that conversation uses. See Media and files |
There is no unauthenticated health or version endpoint: /, which
oar status calls, needs the token.
Share links and preview links are public by design. The link's random token is its only protection, so close or revoke them when you are done. Files the relay serves are sent with a sandbox policy, so a served HTML or SVG file cannot run script on the relay's origin.
The workers' connection only answers requests from the relay's own machine
that no proxy or tunnel forwarded; anything else is refused with 403 before
the token is checked. Shared links through a tunnel are not affected. See
The session-worker path guard.
Protections on sign-in #
- For sign-in and the live connection the relay compares tokens in constant time.
- Added in 0.9.11 Ten wrong tokens lock an address out for a minute. Ten
wrong tokens from one client address within a minute, in a header, the
cookie, the sign-in box or a live-connection handshake, make the relay
answer that address
429withRetry-until the minute is over, the right token included. The sign-in box says Too many failed sign-in attempts. Try again in 42 seconds. The same wrong value repeated counts once, so a tab with an old cookie does not lock you out. The relay logs a line starting withAfter [auth]when it refuses an address. - Requests from the relay's own machine that no proxy or tunnel forwarded are never counted and never locked out, so the relay's workers and the agents' tools keep working.
- The client address is the one the relay trusts. Behind a proxy on another machine that the relay does not trust, every client has the proxy's address, and one client's wrong tokens lock all of them out.
- The lockout slows guessing; it does not replace a good token. Keep the
token long and random:
oar setupgenerates one; do not replace it with a short word. - The one rate limit on routes that need no token is for shared-conversation
presence pings: 24 per 10 seconds for each share link and client address.
Added in 0.9.11 The client address follows
trust, like the lockout, so a client cannot pick its own by sendingProxy X-.Forwarded- For - The token is not written to the log, except when the config has none and
the relay makes a temporary one at start.
oar startandoar urlprint it to your terminal.
Agents and the token #
Your agents run as processes of the user the relay runs as, on the relay's
machine. They do not get credentials of their own: to talk to the relay they
read the relay's own token from config. and send it as the owner would.
The relay does not put the token in an agent's environment or prompt, but an
agent runs as the same operating-system user, so it can read the file and the
token with it. The same goes for anything an agent runs. Treat the token as
known to every agent you run, and run agents only as a user you trust with
the relay.
The relay does not tell agents the token of a paired relay: agents reach a paired relay through this relay, which adds the stored token (Remote relays). An agent also acts with the permissions of the user the relay runs as, so anything the relay's owner can do on the machine, an agent can be asked to do.
Plain HTTP on a LAN #
With LAN access and an http:// address, the token and the cookie cross the
network unencrypted. Anyone who can watch that traffic can read the token. Use
it on a network you trust, or put HTTPS in front. The cookie is not marked
Secure on plain HTTP.
Installing OAR as an app and push notifications need HTTPS or localhost, so
neither works on a plain LAN address: see
Install as an app and
Notifications.
If you think the token leaked #
- Run
oar setup --new-and let it restart the relay. Every browser is signed out. If you decline the restart, runtoken oar restart: until then the old token still works. - Sign in again with the address from
oar url. - On every relay that you paired with this one, add this relay again with the new token (Remote relays).
- Check where the token was stored: scripts, shell history, the address you
pasted into a chat, and copies or backups of
config..json - Stop or renew shared links in Settings → Sharing (Your shared links) and close previews you do not recognize. Those have their own tokens.
- If someone could have used the relay while it was exposed, look at what its agents did. A token holder can start agents that run commands as the relay's user.