.. _howto-login: Sign the CLI in =============== Goal: ``saggar`` authenticated as you, for a human at a laptop or for a script on CI. Prerequisite: an account. Identity is delegated. saggar.dev stores no passwords; your Gitea or GitHub provider owns the login. Sign up once through the web app; the CLI reuses that account. The browser flow ---------------- .. code-block:: console $ saggar login sign in to saggar on https://saggar.dev open this URL in a browser: https://saggar.dev/device then enter the code: KXMJ-4QRT waiting for confirmation… (Ctrl-C cancels; the request expires in 600 s) signed in as @val on https://saggar.dev connection stored in /home/val/.config/saggar/cli.toml The CLI brokers a device login through the service: a provider's redirect URIs are pre-registered, so a web flow cannot end on a localhost port of the CLI's own. The CLI asks the service for an 8-character code, opens (or prints) the verification page, and long-polls until a signed-in visitor types the code there. On the default instance the page is ``https://saggar.dev/device``. The page accepts the code with or without the dash, in any case. When approved, the CLI stores the minted token (``sgt-…``) and prints who it now acts as. Run ``saggar whoami`` to confirm. The headless flow ----------------- Mint a token first, in the web app or on any machine that is already signed in: .. code-block:: console $ saggar token create "ci-runner" --expires-days 90 token id: t-5b249e203f7076f7 expires: 2026-12-27… secret: sgt-… (shown once — store it now) Then hand it to ``login``, which validates it against the server before storing anything: .. code-block:: console $ saggar login --token sgt-… Another instance ---------------- Both flows accept ``--server``; without it, the default instance (``https://api.saggar.dev``) is used: .. code-block:: console $ saggar login --server https://build.example.com:7020 The server you logged in to is stored alongside the token, so every later command hits the same instance. Where credentials live ---------------------- ``~/.config/saggar/cli.toml`` (``$XDG_CONFIG_HOME`` honored; ``$SAGGAR_CONFIG`` points at an explicit file, which must exist): .. code-block:: toml server = "https://build.example.com:7020" token = "sgt-…" How a connection resolves, per invocation; the first non-empty of these wins: 1. the flags (``--server``, ``--token``), 2. the environment (``SAGGAR_SERVER``, ``SAGGAR_TOKEN``), 3. ``cli.toml`` (written by ``saggar login``), 4. the default instance (``https://api.saggar.dev``); no token. This makes CI trivial without touching the stored file: .. code-block:: console $ SAGGAR_TOKEN=sgt-… SAGGAR_SERVER=https://build.example.com saggar submit … Token hygiene ------------- - One token per machine; ``saggar token ls`` lists them, ``saggar token revoke t-…`` kills a lost one immediately. - Credentials that only ever pull from the registries (a docker config, ``apt auth.conf.d``) should be pull-only: ``POST /api/v1/auth/tokens`` with ``{"scope": "registry"}`` (see :doc:`../reference/registries`). Troubleshooting --------------- ``saggar whoami`` answers 401: the stored token expired or was revoked. Log in again.