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 the local UI, which hands off to your identity provider in a browser on the same machine. A headless server has no browser to hand off to.

This page covers the two ways such a machine gets credentials: watcher login, where a person approves the sign-in from a browser on another device, and an organization API key, for machines nobody signs in to.

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
Any machine on a deployment that authenticates through a reverse proxyNothing to do hereThe identity your proxy asserts

The first two 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

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.

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 login. The backend is older than the client and does not offer the endpoints yet. Update the backend, or sign in from a browser: start the client on a machine that has one, or port-forward this machine's local UI (port 8228 by default) to a machine that does.
  • 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.

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.