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/signin 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
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:
--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.
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-upauth verifywould hitNo sign-in request found.auth challengewrites a pending entry (5-minute TTL) thatauth loginconsumes.
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.
--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 stored1β 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.
--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
api --with-sessionbb 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'sgetChallengecurrently hard-codes the scope set; narrower-scope sessions (e.g.Manage Claimsonly) need a small indexer change. Tracked in the backlog.Sessions auto-refresh on use. The indexer runs
express-sessionwithrolling: trueand a 7-day window β every authenticated request resets the cookie's expiry to "now + 7 days" server-side. The CLI captures the rolledSet-Cookiefrom each--with-sessionresponse and writes the newexpiresAtback toauth.json, so a long-lived agent that makes any request inside the rolling window keeps its session indefinitely without re-logging in. Re-runauth loginonly after a stretch of full inactivity longer than the rolling window (or after explicitauth logout).The pending challenge has a 5-minute TTL. If you wait too long between
auth challengeandauth login, the entry is stale andloginwill fetch a fresh challenge (which will not match the message you signed).Shipping
auth.jsonbetween machines is fine β the cookie is just an HTTP cookie. Move the file withscpor equivalent; the receiving box can immediatelybb api --with-session. Keep it0600.
See also
Chain Commands β
sign-arbitraryβ the recommended headless signer that pairs withauth login.API Commands β every indexer route, including
--with-session/--as-address.CLI for AI Agents β end-to-end agent workflow.
Last updated