# Auth Commands

The `bb auth` subcommand authenticates the CLI against the BitBadges indexer using the standard SIWBB (SIWE / EIP-4361) challenge → verify flow. It stores the resulting session cookie under `~/.bitbadges/auth.json` (mode `0600`, multi-account, multi-network), and `bb api --with-session` attaches that cookie on subsequent calls.

This is what an agent or operator runs once before hitting any indexer endpoint gated by `Full Access` — anything that mutates an account, manages keys, publishes signed data, etc. The plain API key is necessary on every call but not sufficient for those routes; the API key is the *app* scope, the session cookie is the *user* scope.

## Wallet-agnostic by design

The CLI **never touches a private key**. Every `auth login` requires a signature produced by something else:

* `bb sign-arbitrary` — the chain binary's offline ADR-36 signer. Recommended for fully headless agents.
* **A browser wallet (MetaMask, Keplr) via `auth login --browser`** — opens `/sign` in your default browser, signs there, captures the signature on a local loopback listener. See [Sign Bridge](/for-developers/cli/sign-bridge.md) for the full reference.
* A hardware wallet, custodial signer, HSM — anything that can produce an ADR-36 / EIP-191 signature over the challenge message. For programmatic / agentic signers that need pre-built SignDoc bytes, see [`gen-tx-payload`](/for-developers/cli/sign-bridge.md#gen-tx-payload).

That separation is what makes the same `auth` surface work for both an agent on a headless box and a developer signing on their laptop.

## Subcommands

| Command                             | Purpose                                                          |
| ----------------------------------- | ---------------------------------------------------------------- |
| [`auth login`](#auth-login)         | One-shot: fetch challenge, post your signature, store the cookie |
| [`auth challenge`](#auth-challenge) | Print a challenge for two-step / external-signer flows           |
| [`auth verify`](#auth-verify)       | Two-step counterpart to `login`                                  |
| [`auth status`](#auth-status)       | List stored sessions; `--check` revalidates server-side          |
| [`auth use`](#auth-use)             | Set the active address for a network                             |
| [`auth whoami`](#auth-whoami)       | Print the active address for the resolved network                |
| [`auth logout`](#auth-logout)       | Sign out and remove the local record                             |
| [`auth path`](#auth-path)           | Print the path of the auth store                                 |

## Common flags

Every `auth` subcommand accepts the same network resolution flags as `bb api`:

| Flag              | Description                                |
| ----------------- | ------------------------------------------ |
| `--testnet`       | Use testnet API                            |
| `--local`         | Use local API (`localhost:3001`)           |
| `--url <url>`     | Custom indexer base URL                    |
| `--api-key <key>` | Override `BITBADGES_API_KEY` for this call |

Networks are isolated in the store — a mainnet and a testnet session for the same address coexist independently.

## Headless flow (recommended for agents)

The canonical agentic flow is three commands. Each step is independent — the only state that crosses them is the `~/.bitbadges/auth.json` file.

```bash
# 1. Fetch a challenge. Saves the nonce cookie locally so step 3 can replay it.
MSG=$(bb auth challenge --address bb1... | jq -r .data.message)

# 2. Sign the challenge with whatever signer you have. Headless Cosmos example:
SIG_JSON=$(bb sign-arbitrary mykey "$MSG")

# 3. Post the signature. Stores the session cookie on success.
bb auth login \
  --address    "$(echo "$SIG_JSON" | jq -r .address)" \
  --signature  "$(echo "$SIG_JSON" | jq -r .signature)" \
  --public-key "$(echo "$SIG_JSON" | jq -r .pubKey)" \
  --message    "$MSG"

# 4. Make a Full Access request. --with-session attaches the cookie.
bb api accounts get-account --body '{"address":"bb1..."}' --with-session
```

> **Why three steps and not one?** The indexer binds each challenge nonce to the response cookie it set on `getChallenge`. Without persisting that cookie locally, a follow-up `auth verify` would hit `No sign-in request found`. `auth challenge` writes a pending entry (5-minute TTL) that `auth login` consumes.

For an interactive flow with an in-process signer, `auth login` will fetch a fresh challenge inline if no pending entry exists and `--message` is not passed.

## Browser-wallet flow

The recommended path for browser-only wallets is the **sign bridge**:

```bash
bb auth login --browser --address bb1...
```

The CLI opens `/sign` in your default browser; you sign with Keplr/MetaMask; the resulting Full Access session lands in `~/.bitbadges/auth.json` automatically. No copy-paste, no `--public-key` to manage. See [Sign Bridge](/for-developers/cli/sign-bridge.md#auth-login-browser) for the full flag reference, the threat model, and SSH-tunneled dev setups.

### Manual paste-in (legacy)

If you want to do it without the bridge — useful for paranoid environments or if the browser auto-launch is undesirable — the same three-step flow works with a paste-in signature:

```bash
# 1. Fetch and print the challenge
bb auth challenge --address 0x...

# 2. Open MetaMask → "Sign Message" → paste the printed message → copy the signature

# 3. Post it back
bb auth login \
  --address 0x... \
  --signature 0x...   # ETH addresses do not require --public-key
```

ETH addresses are detected by the `0x` prefix; Cosmos addresses by `bb1`. `--public-key` is required for Cosmos signatures (the indexer's CosmosDriver verifier needs it) and ignored for ETH.

## auth login

One-shot: fetches a challenge (or reuses a pending one), POSTs the signature, persists the cookie, and marks the address active for the network.

```bash
bb auth login \
  --address <addr> \
  --signature <sig> \
  [--public-key <b64>] \
  [--message <text> | --message-file <path>] \
  [network flags]
```

| Flag                    | Description                                                                                                                                      |
| ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
| `--address <addr>`      | Native address (`bb1...` for Cosmos, `0x...` for ETH). Required.                                                                                 |
| `--signature <sig>`     | Hex or base64 signature over the challenge message. Required unless `--browser` is set.                                                          |
| `--browser`             | Use the [sign bridge](/for-developers/cli/sign-bridge.md) — opens the browser, signs in the wallet there. Mutually exclusive with `--signature`. |
| `--public-key <b64>`    | Compressed pubkey, base64. Required for Cosmos when using `--signature`; auto-captured from the wallet when using `--browser`.                   |
| `--message <text>`      | Exact challenge message. Defaults to the saved pending entry.                                                                                    |
| `--message-file <path>` | Read the challenge message from a file (use `-` for stdin).                                                                                      |
| `--frontend-url <url>`  | With `--browser`: override the frontend base URL.                                                                                                |
| `--no-open`             | With `--browser`: print the sign URL instead of auto-launching the browser.                                                                      |
| `--port <n>`            | With `--browser`: pin the loopback listener port (useful for SSH-tunneled dev).                                                                  |
| `--timeout <seconds>`   | With `--browser`: how long to wait for the wallet (default 300, max 1800).                                                                       |

**Exit codes:**

* `0` — logged in, cookie stored
* `1` — signature rejected, network error, or other failure

## auth challenge

Fetch a SIWBB challenge for an address. Emits the message your signer must sign (at `data.message`) and (by default) persists the response cookie locally so a follow-up `auth login` / `auth verify` can replay it.

```bash
bb auth challenge --address bb1... [--no-save-pending]
# {
#   "ok": true,
#   "data": { "message": "...SIWBB challenge text...", "nonce": "..." },
#   "warnings": [],
#   "error": null
# }

# Extract just the message for a downstream signer:
MSG=$(bb auth challenge --address bb1... | jq -r .data.message)
```

| Flag                | Description                                                                                                                         |
| ------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
| `--address <addr>`  | Native address (`bb1...` or `0x...`). Required.                                                                                     |
| `--no-save-pending` | Do not persist the challenge cookie locally. Advanced — use only if you intend to re-fetch the challenge yourself before verifying. |

## auth verify

Two-step counterpart to `auth login`. Identical surface; kept as a separate subcommand for muscle-memory parity with the `challenge → verify` flow.

```bash
bb auth verify \
  --address <addr> \
  --signature <sig> \
  [--public-key <b64>] \
  [--message <text> | --message-file <path>]
```

## auth status

List stored sessions for the resolved network (or all networks with `--all`). With `--check`, additionally hits `/api/v0/auth/status` to confirm the cookie is still valid server-side.

```bash
bb auth status              # active session on mainnet
bb auth status --all        # every stored session, every network
bb auth status --check      # also revalidate server-side
```

Output lines look like:

```
mainnet   bb1abc...   Cosmos   expires=2026-05-10T03:14:15.000Z (valid) [server: signed-in]
```

## auth use

Set the active address for a network. `bb api --with-session` (without `--as-address`) uses whichever address is active for the resolved network.

```bash
bb auth use bb1abc...
bb auth use bb1xyz... --testnet
```

## auth whoami

Print the active address for the resolved network. Exits non-zero if no session is stored.

```bash
bb auth whoami
bb auth whoami --testnet
```

## auth logout

Sign out and remove the local record. Hits `/api/v0/auth/logout` server-side and deletes the entry from `auth.json`. If the server call fails (network down, cookie already expired), the local record is removed anyway.

```bash
bb auth logout                    # active session on mainnet
bb auth logout --address bb1...   # specific address
bb auth logout --all              # every session, every network
```

## auth path

Print the absolute path of the auth store. Useful for backups, audits, and shipping a session from a laptop to a headless agent box.

```bash
bb auth path
# /home/you/.bitbadges/auth.json
```

## Storage layout

`~/.bitbadges/auth.json` (mode `0600`):

```jsonc
{
  "version": 1,
  "networks": {
    "mainnet": {
      "active": "bb1abc...",
      "sessions": {
        "bb1abc...": {
          "address": "bb1abc...",
          "nativeAddress": "bb1abc...",
          "chain": "Cosmos",
          "cookieName": "bitbadges",
          "cookieValue": "...",
          "scopes": [{ "scopeName": "Full Access" }],
          "createdAt": 1746240000000,
          "expiresAt": 1746844800000,
          "indexerUrl": "https://api.bitbadges.io/api/v0"
        }
      },
      "pending": { /* short-lived challenge state, 5-min TTL */ }
    },
    "testnet": { /* ... */ },
    "local":   { /* ... */ }
  }
}
```

The store is multi-account by design. You can hold sessions for many addresses simultaneously and switch between them with `auth use`, or scope a single call with `bb api ... --as-address <addr>`.

## Using a stored session — `api --with-session`

`bb api` only attaches the cookie when you explicitly ask it to (silent session injection is a footgun):

```bash
# Use the active address for the resolved network
bb api accounts update-account-info \
  --body '{"username":"new"}' \
  --with-session

# Override which stored address to use
bb api accounts update-account-info \
  --body '{"username":"new"}' \
  --with-session --as-address bb1xyz...
```

If the resolved address has no stored session, the call exits 1 with a message pointing you at `auth login`.

## Notes and limitations

* **Scope is `Full Access`.** The indexer's `getChallenge` currently hard-codes the scope set; narrower-scope sessions (e.g. `Manage Claims` only) need a small indexer change. Tracked in the backlog.
* **Sessions auto-refresh on use.** The indexer runs `express-session` with `rolling: true` and a 7-day window — every authenticated request resets the cookie's expiry to "now + 7 days" server-side. The CLI captures the rolled `Set-Cookie` from each `--with-session` response and writes the new `expiresAt` back to `auth.json`, so a long-lived agent that makes any request inside the rolling window keeps its session indefinitely without re-logging in. Re-run `auth login` only after a stretch of full inactivity longer than the rolling window (or after explicit `auth logout`).
* **The pending challenge has a 5-minute TTL.** If you wait too long between `auth challenge` and `auth login`, the entry is stale and `login` will fetch a fresh challenge (which will not match the message you signed).
* **Shipping `auth.json` between machines is fine** — the cookie is just an HTTP cookie. Move the file with `scp` or equivalent; the receiving box can immediately `bb api --with-session`. Keep it `0600`.

## See also

* [Chain Commands — `sign-arbitrary`](/for-developers/cli/chain-commands.md) — the recommended headless signer that pairs with `auth login`.
* [API Commands](/for-developers/cli/api-commands.md) — every indexer route, including `--with-session` / `--as-address`.
* [CLI for AI Agents](/for-developers/cli/for-ai-agents.md) — end-to-end agent workflow.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.bitbadges.io/for-developers/cli/auth-commands.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
