Skip to content
Jörg Thalheim edited this page May 10, 2026 · 3 revisions

Client 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.

File-backed tokens (--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

Script-backed tokens (--auth-token-script)

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}\"'"

Example: GitHub Actions OIDC

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-token

The daemon refreshes the token before each batch when needed; large closures that take longer than 5 minutes to upload no longer fail with 401.

Example: HashiCorp Vault

--auth-token-script "vault read -format=json secret/niks3-token"

(adapt the JSON shape with a small wrapper if needed.)

mTLS client certificates

When the server sits behind a reverse proxy that verifies client certificates, the cert is the credential — no bearer token required. See mTLS.

Server side

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.

Clone this wiki locally