Signing in without a browser
The usual way to sign the Watcher client in is a
browser on the same machine. Running watcher from a desktop terminal, or
choosing Sign in to Watcher in the macOS menu bar, opens the client's
sign-in page, which hands off to your identity provider. A headless server has
no browser to open it in.
Use watcher login for a person who approves SSO from another device, an
organization API key for an unattended SSO deployment, or an
external credential helper when a proxy deployment
requires tokens from your company CLI.
Choose how the machine authenticates
| The machine | Use | Sessions are attributed to |
|---|---|---|
| A server or VM a person reaches over SSH, even if nobody stays logged in | watcher login | The person who approved the sign-in |
| Unattended: CI, a container nobody logs in to, a shared runner | WATCHER_API_KEY | The organization, not a person |
| A container on a developer machine that is already signed in | The host's credentials, bind-mounted | The host's user |
| A proxy deployment that requires renewable bearer tokens | External credential helper | The identity validated by your gateway |
| A proxy deployment with another gateway authentication mechanism | Configure the gateway and any required client headers | The identity your proxy asserts |
The SSO options are below. For the container cases, see
Containers, which compares all
of them for that setting. On a proxy-authenticated deployment the gateway
signs requests in, so terminal sign-in does not apply and watcher login
says so.
Terminal sign-in
Before you start
- The client is installed on the machine, and either
watcher target set --cloudorwatcher target set --url https://<your-watcher-host>has recorded which backend it talks to. - The deployment uses SSO. Terminal sign-in is a sign-in flow, so it only applies where there is an identity provider to sign in to.
- You have a browser on some other device: a laptop, a phone. It does not need any network route to the headless machine.
Sign in
Run this on the headless machine, over SSH:
watcher login
watcher auth login is an alias for the same sign-in flow.
It prints a URL and a short code, then waits:
Signing in to https://watcher.example.com
On any device with a browser, open:
https://id.example.com/device?user_code=ABCD-EFGH
and confirm it shows this code: ABCD-EFGH
Waiting for approval (the code expires in 5 minutes; Ctrl-C to cancel)...
Open that URL on the other device, sign in as you normally would, and check that the page shows the same code the terminal printed. Confirming the code is what ties your approval to this specific machine, so compare the two rather than clicking through.
The command returns once you approve:
Signed in as person@example.com.
Credentials saved to /home/dev/.apollo_monitor/credentials/production.json.
Those are the same credentials the browser flow writes, in the same place, so the hooks, the background client, and token refresh all behave identically from here on. You do not need to repeat this after a reboot: the credentials are refreshed on use, including after the machine has been off for a while.
Transcript uploads use the latest saved credentials for the account and
organization captured when the upload was queued. Switching accounts or
organizations stops an in-progress upload before it sends with the new identity.
If a transcript upload or a request for settings or grading information is rejected because its access
token expired, Watcher attempts to refresh it and retry the rejected request once. If your sign-in
session has expired or been revoked, sign in again with watcher login.
Keep the client running
Signing in stores credentials. It does not start the client, and on a server nobody stays logged into, starting it once is not enough either.
Run the client once so it installs the login agent, the service that starts it and keeps it running. It starts in the background and returns control to the terminal:
watcher
On Linux that agent is a systemd user unit, which starts at login and stops with the user's last session. A server running agents unattended needs the user instance to survive logout and reboot. Enable lingering for the user you signed in as, the one whose home holds the credentials:
loginctl enable-linger <user>
Without lingering, sign-in and watcher doctor both look healthy while
someone is logged in, and nothing records once they disconnect.
Verify
watcher doctor
The auth check confirms that credentials exist for this target and that a
live authenticated request succeeds. Then start a coding agent session on the
machine and confirm it appears in the Analyzer.
If it does not complete
- The code expired. It is valid for the few minutes the command prints, so
a delay in getting to the other device runs it out. Run
watcher loginagain for a fresh code. - You cancelled or denied the sign-in in the browser. Run
watcher loginagain. - The command reports that the server predates device sign-in. The backend is
older than the client and does not offer the endpoints yet. Update the
backend, or sign in through a browser on another machine:
- On the machine with the browser, free port 8228. If its own Watcher
client holds the port, stop it:
watcher autostart stopstops one the login agent runs, and one started withwatcher --foregroundstops in its own terminal. That machine records nothing and runs no blocking review until its client starts again, for example withwatcher autostart start. - Make sure this machine's client is running (run
watcherif it is not), then forward the browser machine's port 8228 to it, from the browser machine:ssh -L 8228:localhost:8228 <user>@<headless-host>. If this machine's client uses another port throughWATCHER_BACKEND_PORT, put that port afterlocalhost:. - Open
http://localhost:8228/loginin that machine's browser. Keep port 8228 and the namelocalhoston the browser side, because sign-in sends the browser back to that address.
- On the machine with the browser, free port 8228. If its own Watcher
client holds the port, stop it:
- The command reports that the deployment does not use SSO sign-in. It authenticates through a reverse proxy, and the gateway supplies the identity. See Sending additional headers.
Signing out
Run this on the machine whose stored sign-in you want to remove:
watcher logout
watcher auth logout is an alias. The command asks the selected backend to
end the stored sign-in's session, then deletes the stored credentials.
Sign-out on the machine completes even if that request fails: the backend may
be unreachable, refuse the request, or send an answer the client cannot read.
A warning then says that the server session may stay active until it expires.
A backend that accepts the request does not report whether the session ended,
so Watcher cannot confirm that it did. Your browser may also still be signed
in to your identity provider. The background client keeps running and stops
using the deleted credentials.
API keys and captured authentication headers are unchanged, and either one may
still authenticate Watcher. The command mentions them when it finds captured
headers, or an API key in the environment it runs in. With no other usable
credential on an SSO deployment, the hooks stop recording and grading until
you sign in again, and the coding agent's own permission prompts still apply.
Run watcher doctor to check which authentication method remains. An
external credential helper owns its own sign-in, so
the command refuses to run: sign out with your company's sign-in tool
instead.
If the command reports a local file error, sign-out did not finish. Check the
permissions of ~/.apollo_monitor, then run watcher logout again.
On a machine with a browser, Sign out on the page at
http://localhost:8228 does the same as watcher logout. The page shows it
while a browser or watcher login sign-in authenticates the machine. After
signing out, the browser stays on a confirmation page. A successful request
shows Start sign-in so you can choose when to sign in again. The
confirmation page does not start sign-in automatically. If the request to
the backend failed, the page warns
that the server session may stay active until it expires instead.
Unattended machines
Terminal sign-in needs a person to approve it. A machine nobody signs in to, such as a CI runner or a container started by an agent, authenticates with an organization API key instead:
export WATCHER_API_KEY=<key>
The hooks and the client both read it from the environment, so set it where the machine's processes will actually see it: the runner's environment configuration, the container's run command, or the service definition that starts the client. Exporting it in one SSH session leaves every other process without it.
Create and revoke these keys on the API Keys tab in the Analyzer, described in Organization settings.
Sessions recorded this way are attributed to the organization rather than to a
person, which is the tradeoff for not having anyone to attribute them to. Where
a person does own the machine, prefer watcher login, so its sessions carry
their identity.