Skip to main content
Working with an agent? Give them a link to this page as markdown.

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 machineUseSessions are attributed to
A server or VM a person reaches over SSH, even if nobody stays logged inwatcher loginThe person who approved the sign-in
Unattended: CI, a container nobody logs in to, a shared runnerWATCHER_API_KEYThe organization, not a person
A container on a developer machine that is already signed inThe host's credentials, bind-mountedThe host's user
A proxy deployment that requires renewable bearer tokensExternal credential helperThe identity validated by your gateway
A proxy deployment with another gateway authentication mechanismConfigure the gateway and any required client headersThe 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 --cloud or watcher 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 login again for a fresh code.
  • You cancelled or denied the sign-in in the browser. Run watcher login again.
  • 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:
    1. On the machine with the browser, free port 8228. If its own Watcher client holds the port, stop it: watcher autostart stop stops one the login agent runs, and one started with watcher --foreground stops in its own terminal. That machine records nothing and runs no blocking review until its client starts again, for example with watcher autostart start.
    2. Make sure this machine's client is running (run watcher if 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 through WATCHER_BACKEND_PORT, put that port after localhost:.
    3. Open http://localhost:8228/login in that machine's browser. Keep port 8228 and the name localhost on the browser side, because sign-in sends the browser back to that address.
  • 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.