-
Notifications
You must be signed in to change notification settings - Fork 30
Authentication
niks3 push, niks3 gc, and niks3-hook serve authenticate to the server
with a bearer token. The token can come from one of three sources, chosen by
flag:
| Flag | Source | Refresh |
|---|---|---|
--auth-token-path FILE |
reads a file | re-read at most once per minute |
--auth-token-script CMD |
runs a command | cached until 75% of expires_at lifetime |
If none of the flags is set, niks3 falls back to reading the file at
$NIKS3_AUTH_TOKEN_FILE or $XDG_CONFIG_HOME/niks3/auth-token — both behave
like --auth-token-path.
The simplest option. Put the token in a file and point niks3 at it:
niks3 push --server-url https://cache.example.com \
--auth-token-path /run/secrets/niks3-token \
/nix/store/...The file is re-read lazily (at most once per minute), so an external process
may rotate it while a long-running niks3-hook serve daemon is up. This
mirrors the Kubernetes projected-service-account-token pattern: a sidecar or
systemd timer keeps the file fresh; niks3 only needs to notice eventually.
Suitable for:
- static API tokens managed by sops/vault-agent/systemd
LoadCredential - any environment with an external token refresher writing to a file
For short-lived tokens that need to be minted on demand (OIDC, vault, AWS STS), use a script. The command must print a single JSON object on stdout:
{"token": "eyJhbGci...", "expires_at": "2026-05-10T14:30:00Z"}expires_at is RFC 3339. When present, niks3 caches the token and reruns the
script after 75% of the observed lifetime has elapsed. When absent, the
script runs on every authenticated request — only do this if the script
caches internally (e.g. aws sts, vault token lookup).
Logs and progress should go to stderr; stdout must contain only the JSON.
This mirrors the AWS credential_process and Kubernetes
ExecCredential conventions.
niks3 push --server-url https://cache.example.com \
--auth-token-script "/usr/local/bin/fetch-niks3-token" \
/nix/store/...The command string is split with shell-like quoting (single/double quotes,
backslash escapes), but no expansion or substitution runs — $VAR and
`cmd` are passed literally. If you need pipes or variables, wrap the
command explicitly:
--auth-token-script "sh -c 'curl -s \"$TOKEN_URL\" | jq \"{token: .access_token}\"'"GitHub Actions OIDC tokens last ~5 minutes. A token script that mints one:
#!/bin/sh
# fetch-gha-oidc-token
exec curl -sf \
-H "Authorization: Bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" \
"$ACTIONS_ID_TOKEN_REQUEST_URL&audience=https://cache.example.com" \
| jq '{token: .value, expires_at: ((now + 240) | todateiso8601)}'Then:
niks3-hook serve --server-url https://cache.example.com \
--auth-token-script /path/to/fetch-gha-oidc-tokenThe daemon refreshes the token before each batch when needed; large closures that take longer than 5 minutes to upload no longer fail with 401.
--auth-token-script "vault read -format=json secret/niks3-token"(adapt the JSON shape with a small wrapper if needed.)
When the server sits behind a reverse proxy that verifies client certificates, the cert is the credential — no bearer token required. See mTLS.
The server validates incoming bearer tokens against its API token
(--api-token-path), its OIDC providers (--oidc-config), or accepts
verified mTLS client certs via --mtls-proxy-header. See OIDC
and mTLS.