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

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

One-shot: fetch challenge, post your signature, store the cookie

Print a challenge for two-step / external-signer flows

Two-step counterpart to login

List stored sessions; --check revalidates server-side

Set the active address for a network

Print the active address for the resolved network

Sign out and remove the local record

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.

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

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:

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

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.

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 β€” 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.

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.

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.

Output lines look like:

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.

auth whoami

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

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.

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.

Storage layout

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

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):

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

Last updated