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¶
$ 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:
$ 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:
$ saggar login --token sgt-…
Another instance¶
Both flows accept --server; without it, the default instance
(https://api.saggar.dev) is used:
$ 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):
server = "https://build.example.com:7020"
token = "sgt-…"
How a connection resolves, per invocation; the first non-empty of these wins:
the flags (
--server,--token),the environment (
SAGGAR_SERVER,SAGGAR_TOKEN),cli.toml(written bysaggar login),the default instance (
https://api.saggar.dev); no token.
This makes CI trivial without touching the stored file:
$ SAGGAR_TOKEN=sgt-… SAGGAR_SERVER=https://build.example.com saggar submit …
Token hygiene¶
One token per machine;
saggar token lslists 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/tokenswith{"scope": "registry"}(see The registries).
Troubleshooting¶
saggar whoami answers 401: the stored token expired or was
revoked. Log in again.