---
summary: Use the SigID CLI for local agent keys, registration, challenge-response authentication, signing, token caching, and key lifecycle workflows.
tags:
  - cli
  - agents
  - keys
  - registration
  - authentication
categories:
  - AI Agents
---

# CLI Tool

<!-- agent:page
You are a coding agent or operator using sigid-cli for local agent identity workflows by following this reference.
First collect: IDP URL, tenant context if needed, local key label, key algorithm, passphrase source, requested scopes, output format, and whether the task is init, auth, token inspection, x402 payment, signing, verification, key rotation, or revocation.
Use init for first-time local registration, auth for challenge-response token acquisition, token commands for cache inspection or refresh, x402 commands only after a valid cached agent token exists, and key commands for local keystore and server key lifecycle.
Keep keystore and token-cache files private, avoid passphrases in shell history, require HTTPS for non-localhost IDPs, and never print private keys, token cache contents, or passphrases into logs.
Verify the command result, exit status, selected IDP, selected key label, token subject type, and key lifecycle state before reporting success.
-->

The SigID CLI (`sigid-cli`) is the command-line interface for agent identity
workflows. It covers local key management, agent registration,
challenge-response authentication, token caching, signing, verification, and key
lifecycle operations.

This CLI is not a Dashboard administration tool or a general Management API
client. For interactive human login from a terminal it supports OAuth device
authorization via `auth --mode device`. For HTTP API integration patterns, see
[API And SDK Reference](../reference/api-sdk-reference.md).

## What this page is for

Use this page when you need to:

- generate and store agent signing keys locally
- initialize a self-registered agent from a terminal
- authenticate an agent with challenge-response
- inspect cached agent tokens
- buy x402-protected resources as an authenticated agent
- sign and verify local payloads
- register, rotate, revoke, or remove agent keys
- script agent identity operations in development or CI

## Install and verify

### From npm (recommended)

Prebuilt native binaries for Linux and macOS (x64 / arm64):

```bash
npx @sigid/cli --version
npx @sigid/cli setup --name my-agent --redirect-uri http://localhost:3000/

# or install globally / as a project dependency
npm install -g @sigid/cli
sigid-cli --help
```

The `@sigid/cli` package is a thin Node wrapper; the real tool is the
platform-specific `sigid-cli` binary shipped via optionalDependencies
(`@sigid/cli-linux-x64`, `@sigid/cli-linux-arm64`, `@sigid/cli-darwin-x64`,
`@sigid/cli-darwin-arm64`).

The Linux x64 and arm64 packages use statically linked musl binaries and do
not require a particular glibc version from the host environment.

### From source

```bash
cargo install --path crates/sigid-cli
```

Use source install on unsupported platforms (e.g. Windows) or when developing
the CLI itself.

Verify the installed binary:

```bash
sigid-cli --version
sigid-cli --help
```

## Before you start

The CLI stores local configuration and sensitive data under `~/.config/sigid/`
unless your environment overrides the platform config directory.

| File | Purpose | Notes |
|---|---|---|
| `~/.config/sigid/config.toml` | CLI defaults | Plain TOML configuration |
| `~/.config/sigid/keys.enc` | Local private-key keystore | Encrypted with Argon2id + AES-256-GCM-SIV |
| `~/.config/sigid/tokens.enc` | Cached access and refresh tokens | Encrypted token cache |
| `~/.config/sigid/tokens.key` | Token-cache master key | Private file permissions |

Passphrase sources are checked in this order:

1. `--passphrase`
2. `--passphrase-stdin`
3. `--passphrase-file`
4. `SIGID_PASSPHRASE`
5. interactive prompt

`--passphrase` exists for automation and tests, but it can be captured in shell
history. Prefer an interactive prompt, `--passphrase-stdin`,
`--passphrase-file`, or `SIGID_PASSPHRASE` in controlled CI environments.

## Initialize an agent

`init` generates a key pair, registers the agent, and caches credentials in one
flow.

```bash
sigid-cli init \
  --idp https://auth.example.com \
  --tenant-id 018f3d44-7d4d-7d5d-8d3b-9f0c4c37a111 \
  --name my-agent \
  --anchor-type did_key \
  --algo ed25519
```

| Option | Description | Default |
|---|---|---|
| `--idp` | Identity Provider URL | `default_idp` from config, otherwise required |
| `--tenant-id` | Tenant ID bound into the key-ownership proof | `default_tenant_id` from config, otherwise required |
| `--name` | Agent name and local key label | Required |
| `--anchor-type` | Agent anchor type | `did_key` |
| `--algo` | Key algorithm | `ed25519` |

The CLI:

- generates a local key pair
- registers the agent with `/api/v1/agents/auth/register`
- falls back to PoW registration through `/api/v1/agents/auth/register/pow` and
  `/api/v1/agents/auth/register/pow/complete` when required
- stores the private key in `keys.enc`
- caches returned tokens when the tenant admits the agent

## Hand Off An Agent-Built Workspace

After provisioning and testing, transfer durable ownership of the agent and
grant the developer the resources needed to inspect the integration:

```bash
sigid-cli handoff \
  --idp https://auth.example.com \
  --organization-id 018f3d44-7d4d-7d5d-8d3b-9f0c4c37a111 \
  --agent-id 018f3d44-7d4d-7d5d-8d3b-9f0c4c37a222 \
  --application-id 018f3d44-7d4d-7d5d-8d3b-9f0c4c37a333
```

`--application-id` is repeatable. Organization co-ownership is granted by
default; pass `--grant-org-owner=false` only for an agent/application-only
transfer. Send the returned fragment-bearing link privately to the intended
developer. Acceptance is single-use and transfers the agent's durable owner.

This differs from `invite`: an invitation grants organization/application
access but never transfers the agent identity. See
[Provision, Test, And Hand Off](provision-test-handoff.md) for the fixture-user,
branding, test-manifest, and acceptance sequence.

## Authenticate

`auth` supports three modes via `--mode`:

| Mode | Purpose |
|---|---|
| `agent` (default) | Challenge-response with an existing local agent key |
| `autonomous` | Create a new agent identity (keygen + register), then authenticate |
| `device` | OAuth device flow: print a link, user logs in in a browser, CLI polls for tokens |

### Agent mode (challenge-response)

```bash
sigid-cli auth \
  --idp https://auth.example.com \
  --key my-agent \
  --scope "openid wallet:sign"
```

| Option | Description | Default |
|---|---|---|
| `--mode` | `agent`, `autonomous`, or `device` | `agent` |
| `--idp` | Identity Provider URL | `default_idp` from config, otherwise error |
| `--key` | Local key label to use | `default_key` from config, otherwise `default` |
| `--scope` | Requested scopes | None |

The CLI:

- loads the local key from the encrypted keystore
- requests `/api/v1/agents/auth/challenge`
- signs the canonical challenge
- submits `/api/v1/agents/auth/verify`
- stores the returned tokens in `tokens.enc`

### Autonomous mode (self-register)

Creates a new agent identity the same way as `init`, then runs challenge-response
auth with the new key. Emits **one** result (registration facts + bearer).

Non-interactive use requires a passphrase source (`SIGID_PASSPHRASE`,
`--passphrase-file`, or `--passphrase-stdin`). There is no plaintext key-on-disk
mode; the local keystore always stays encrypted. Interactive prompts work when a
TTY is available.

```bash
export SIGID_PASSPHRASE='...'
sigid-cli auth --mode autonomous \
  --idp https://auth.example.com \
  --tenant-id 018f3d44-7d4d-7d5d-8d3b-9f0c4c37a111 \
  --name my-agent \
  --algo ed25519
```

| Option | Description | Default |
|---|---|---|
| `--name` / `--key` | Agent name and local key label | `default_key` / `default` |
| `--tenant-id` | Tenant bound into the key-ownership proof | `default_tenant_id`, otherwise required |
| `--algo` | Key algorithm | `ed25519` |
| `--anchor-type` | Agent anchor type | `did_key` |

### Device mode (OAuth link login)

RFC 8628 device authorization for human login from a terminal. The application
must allow the `device_code` grant and the tenant must have device flow enabled.

```bash
sigid-cli auth --mode device \
  --idp https://auth.example.com \
  --client-id YOUR_CLIENT_ID \
  --scope "openid profile offline_access"
```

| Option | Description | Default |
|---|---|---|
| `--client-id` | OAuth application client id | Required |
| `--scope` | Requested scopes (include `offline_access` for a refresh token) | None |
| `--tenant-slug` | Optional tenant routing on the token poll (persisted for refresh) | None |
| `--interval` | Initial poll interval seconds | Server `interval` or 5 |

The CLI:

- calls `POST /oauth/device/code`
- always prints the absolute verification link and user code on **stderr**
  (including under `--output json|yaml|quiet`) so the human can open the link
  while the CLI blocks on the poll loop
- polls `POST /oauth/token` with grant
  `urn:ietf:params:oauth:grant-type:device_code`
- honors `authorization_pending`, `slow_down`, `access_denied`, and
  `expired_token`
- caches the human token in `tokens.enc` (`subject_kind=user`, with
  `client_id` and optional `tenant_slug` so `sigid-cli token --refresh` uses
  `/oauth/token`)
- omits refresh tokens and ID tokens from every output format; refresh tokens
  remain available only through the encrypted token cache

This is distinct from `sigid-cli delegation`, which is agent-initiated AAL2
approval for a **delegated agent** token, not a human OAuth session.

## Inspect identity and tokens

Show the current local identity and cached agent context:

```bash
sigid-cli whoami
```

Show a cached token for an IDP:

```bash
sigid-cli token --idp https://auth.example.com
```

Refresh a cached token:

```bash
sigid-cli token --refresh --idp https://auth.example.com
```

Clear cached tokens:

```bash
# Clear tokens for one IDP
sigid-cli token --clear --idp https://auth.example.com

# Clear all cached tokens
sigid-cli token --clear
```

## Buy x402-protected resources

`x402 buy` quotes and immediately executes an outbound x402 purchase using the
cached agent token for the IDP.

```bash
sigid-cli x402 buy \
  --idp https://auth.example.com \
  --url https://merchant.example.com/resource \
  --header "Accept: application/json"
```

The CLI calls the agent-authenticated `/agent/x402/pay/quote` route first, then
executes the returned quote through `/agent/x402/pay/execute`. Run
`sigid-cli auth` first if no valid cached token is available.

For merchants using SigID Commerce payment links, use `x402 commerce-link`.
The CLI builds the commerce x402 endpoint and pays it through the same agent
outbound x402 flow:

```bash
sigid-cli x402 commerce-link \
  --idp https://auth.example.com \
  --merchant https://merchant.example.com \
  --payment-link-token plink_abc123 \
  --buyer-country US \
  --buyer-type business
```

| Option | Description | Default |
|---|---|---|
| `--idp` | Identity Provider URL | `default_idp` from config, otherwise error |
| `--url` | x402-protected resource URL | Required |
| `--method` | Outbound method: `GET` or `HEAD` | `GET` |
| `--header` | Outbound header; only `Accept` and `Accept-Language` are supported | None |
| `--payment-route` | `facilitator` or `wallet` | `facilitator` |
| `--payer-mode` | `sigid_funded`, `user_authorized`, or `tenant_funded` | `sigid_funded` |
| `--idempotency-key` | Caller idempotency key bound to the quote | None |
| `--payment-required-file` | JSON file containing a captured x402 402 response body | None |
| `--payment-payload-file` | JSON file containing a signed x402 payment payload for `user_authorized` mode | None |

`x402 commerce-link` additionally accepts:

| Option | Description | Default |
|---|---|---|
| `--merchant` | Merchant SigID Commerce origin | Required |
| `--payment-link-token` | SigID Commerce payment-link token | Required |
| `--buyer-country` | Buyer country for merchant policy checks | None |
| `--buyer-region` | Buyer region for merchant policy checks | None |
| `--buyer-type` | `unknown`, `consumer`, or `business` | None |

For manual quote and execution flows:

```bash
sigid-cli x402 quote \
  --idp https://auth.example.com \
  --url https://merchant.example.com/resource

sigid-cli x402 execute \
  --idp https://auth.example.com \
  --quote-id 018f3d44-7d4d-7d5d-8d3b-9f0c4c37a111

sigid-cli x402 status \
  --idp https://auth.example.com \
  --payment-id 018f3d44-7d4d-7d5d-8d3b-9f0c4c37a111
```

Outbound x402 quotes are short lived. Execute a quote immediately, or use
`x402 buy` for the normal one-step purchase path.

## Manage local keys

Generate a local key pair:

```bash
sigid-cli keygen --algo ed25519 --label my-agent
```

| Option | Description | Default |
|---|---|---|
| `--algo` | Key algorithm: `ed25519`, `es256`, `es256k`, or `bip340` | `ed25519` |
| `--label` | Local key label | `default_key` from config, otherwise `default` |

`keygen` prints the public key and fingerprint. It does not print the private
key. The private key is encrypted and stored in the local keystore.

List local keys:

```bash
sigid-cli list-keys
```

Remove a key from the local keystore:

```bash
sigid-cli remove-key --key old-key
```

`remove-key` only deletes the local keystore entry. To revoke a registered key
on the IDP, use `revoke-key`.

## Register, rotate, and revoke keys

Register an additional local key with the IDP:

```bash
sigid-cli register-key \
  --idp https://auth.example.com \
  --tenant-id 018f3d44-7d4d-7d5d-8d3b-9f0c4c37a111 \
  --key backup-key
```

`register-key` requires a valid cached token. Run `sigid-cli auth` first if no
valid token is available. `--tenant-id` (or `default_tenant_id` in config) is
required for the key-ownership proof.

Rotate a key:

```bash
sigid-cli rotate-key \
  --idp https://auth.example.com \
  --tenant-id 018f3d44-7d4d-7d5d-8d3b-9f0c4c37a111 \
  --old my-agent \
  --new-label my-agent-v2
```

| Option | Description | Default |
|---|---|---|
| `--tenant-id` | Tenant ID for the new key's ownership proof | `default_tenant_id` from config, otherwise required |
| `--old` | Label of the old local key | Required |
| `--new-label` | Label for the new key | `{old}_v2` |
| `--new-algo` | Algorithm for the new key | Same as old key |

The CLI generates a new key pair, registers the new key, saves it locally, and
deprecates the old key on the IDP.

Deprecate a registered key without rotating:

```bash
sigid-cli deprecate-key \
  --idp https://auth.example.com \
  --key old-key
```

Revoke a key:

```bash
sigid-cli revoke-key \
  --idp https://auth.example.com \
  --key compromised-key \
  --reason "key exposed"
```

`deprecate-key` soft-retires a key on the IDP (normal lifecycle). `revoke-key`
marks the registered key as compromised. Both preserve the local key; use
`remove-key` to delete the local keystore entry.

Change the keystore passphrase (re-encrypts all local keys under a new Argon2id
salt):

```bash
sigid-cli change-passphrase
```

## Sign and verify payloads

Sign a message:

```bash
sigid-cli sign --message "Hello, SigID!" --key my-agent
```

Sign a file:

```bash
sigid-cli sign --file transaction.json --key my-agent
```

The signature output includes a base64-encoded signature, algorithm,
fingerprint, and timestamp.

Verify a message signature:

```bash
sigid-cli verify \
  --message "Hello, SigID!" \
  --signature "base64-signature" \
  --public-key "hex-encoded-public-key" \
  --algo ed25519
```

Verify a file signature:

```bash
sigid-cli verify \
  --file transaction.json \
  --signature-file transaction.sig \
  --public-key "hex-encoded-public-key" \
  --algo ed25519
```

`--signature` expects a base64-encoded signature. `--signature-file` reads a raw
binary signature file.

Create a GPG-compatible detached signature:

```bash
sigid-cli gpg-sign --file artifact.tar.gz --key my-agent
sigid-cli gpg-sign --file artifact.tar.gz --key my-agent --armor
```

Without `--armor`, the CLI writes a binary `.sig` file. With `--armor`, it
writes a `.sig.asc` file.

## Configuration and storage

Set defaults with the `config` subcommand (preferred) or by editing
`~/.config/sigid/config.toml`:

```bash
sigid-cli config set \
  --default-idp https://auth.example.com \
  --default-key my-agent \
  --default-tenant-id 018f3d44-7d4d-7d5d-8d3b-9f0c4c37a111 \
  --output-format json
sigid-cli config show
```

```toml
default_idp = "https://auth.example.com"
default_key = "my-agent"
default_tenant_id = "018f3d44-7d4d-7d5d-8d3b-9f0c4c37a111"
output_format = "json"
```

| Field | Description |
|---|---|
| `default_idp` | Default Identity Provider URL (`--idp` → config → error; setup/invite/handoff/verify-setup fall back to `https://auth.sigid.org`) |
| `default_key` | Default local key label |
| `default_tenant_id` | Default tenant ID for key-ownership proofs on `init` / `register-key` / `rotate-key` |
| `output_format` | Default output format when `--output` is omitted: `json`, `yaml`, `text`, `table`, or `quiet` |

Supported environment variables:

| Variable | Purpose |
|---|---|
| `SIGID_PASSPHRASE` | Keystore passphrase for automation |
| `SIGID_LOG_LEVEL` | CLI logging level |
| `RUST_LOG` | Fallback logging configuration |

Supported global flags:

```bash
--output json|yaml|text|quiet|table
--keystore /path/to/keys.enc
```

Non-localhost IDP URLs must use HTTPS. Local development URLs such as
`http://localhost:3000` and `http://auth.sigid.localhost:3000` are allowed;
the CLI bypasses proxies and pins `.localhost` names to loopback addresses.

## Output formats and scripting

JSON is the default output format:

```bash
sigid-cli whoami --output json
```

Other formats are available for humans and scripts:

```bash
sigid-cli list-keys --output table
sigid-cli token --output quiet   # raw access token only
sigid-cli sign --message hi --output quiet   # raw signature only
sigid-cli whoami --output yaml
```

Quiet mode emits primary machine-parseable values (raw bearer for `token` /
`auth`, raw signature for `sign`, newline-separated labels for `list-keys`)
instead of the human Display block. Table uses the same columnar layout as text
for list-like results.

The CLI exits with `0` on success and a non-zero code on errors.

## Keystore security

The local keystore is designed for agent development and operator workflows:

- private keys are encrypted at rest in `keys.enc`
- the keystore uses Argon2id-derived keys and AES-256-GCM-SIV encryption
- keystore and token files are written atomically with restrictive permissions
- the token cache is encrypted separately from the private-key keystore
- non-localhost IDP URLs must use HTTPS to avoid exposing bearer tokens

Keep the keystore passphrase outside source control and avoid passing it through
shell history.

## Common errors

| Error | Meaning | Fix |
|---|---|---|
| `no IDP URL specified` | No `--idp` flag and no `default_idp` in config | Pass `--idp` or `sigid-cli config set --default-idp …` |
| `no tenant ID specified` | No `--tenant-id` and no `default_tenant_id` | Pass `--tenant-id` or set `default_tenant_id` |
| `no valid token - authenticate first with sigid-cli auth` | The IDP operation needs a cached token | Run `sigid-cli auth` |
| `no refresh token available` | The cached token cannot be refreshed | Re-authenticate with `sigid-cli auth` |
| `key '<name>' has no server_key_id` | The local key has not been registered with the IDP | Run `sigid-cli register-key` first |
| `default_idp must use https for non-localhost hosts` | Remote IDP URL uses plain HTTP | Use HTTPS for non-localhost IDPs |
| `provide --message or --file` | Signing or verification input is missing | Pass one input source |
| `provide --signature or --signature-file` | Verification signature is missing | Pass one signature source |
| Signature verification failure | Payload, public key, algorithm, or signature does not match | Re-check the exact bytes and algorithm |

## Command reference

| Command | Purpose |
|---|---|
| `setup` | Workspace bootstrap (agent + sandbox org/env/app) |
| `init` | Generate a key, register an agent, and cache tokens |
| `invite` | Issue operator co-owner invitation link |
| `handoff` | Transfer agent ownership plus optional organization/application access to a human |
| `verify-setup` | OIDC discovery + local token check after setup |
| `app create\|list\|get\|update\|rotate-secret` | Tenant OAuth application management (`update` merges onto current state) |
| `delegation create\|poll\|revoke` | Agent device-flow human delegation + issued-delegation revocation |
| `keygen` | Generate a local key pair |
| `sign` | Sign a message or file |
| `verify` | Verify a signature |
| `gpg-sign` | Create a GPG-compatible detached signature |
| `auth` | Perform agent challenge-response authentication |
| `token` | Show, refresh, or clear cached tokens |
| `register-key` | Register a local key with the IDP |
| `list-keys` | List local keystore entries |
| `whoami` | Show local identity and cached agent context |
| `rotate-key` | Generate and register a replacement key, then deprecate the old key |
| `deprecate-key` | Soft-retire a registered key on the IDP |
| `revoke-key` | Revoke a registered key on the IDP |
| `remove-key` | Remove a key from the local keystore |
| `change-passphrase` | Re-encrypt the local keystore under a new passphrase |
| `config show\|set\|unset` | Read or write CLI defaults (`default_idp`, `default_tenant_id`, …) |
| `x402` | Quote/execute outbound x402 payments |
| `schema export` | Export database schema for development or operator workflows |

## See also

- [Agent Self-Serve Quickstart](agent-quickstart.md)
- [Provision, Test, And Hand Off](provision-test-handoff.md)
- [Agent Authentication](agent-auth.md)
- [Agent Registration](registration.md)
- [API And SDK Reference](../reference/api-sdk-reference.md)
