Skip to content
authgrabber

CLI reference

All authgrabber commands.

Command-line interface reference for the authgrabber binary. For the phase plan and design rationale, see docs/design.md.

authgrabber captures the browser’s authenticated state from the active Firefox profile and hands it to an automated browser (obscura). Concretely:

  • Session / SSO cookies (cookies.sqlite): the cookies that keep you signed in across apps (a single sign-on cookie plus per-app session cookies).
  • Opaque cookies at or above 128 characters are flagged as auth candidates.
  • Stored OAuth tokens (webappsstore2.sqlite = localStorage): access, refresh, and id tokens.
  • Tokens are classified by key name (access_token, refresh_token, id_token, …), by JWT shape (eyJ...), or by being a long opaque cookie.
  • JWT payloads are decoded for the claims exp, iat, iss, sub, aud, scope, name, email, picture.
  • Fresh tokens on demand: the login command runs the active authorization-code flow (PKCE) to mint a new token instead of reusing what is already stored.
  • Saved logins (logins.json / key4.db): the password manager’s stored usernames and passwords, decrypted via the logins command using Firefox’s NSS library.

Every command targets exactly one profile: the active profile by default (the one Firefox runs), or a specific one you pass as [PROFILE] (a profile name matching Name=, or an absolute path).

It does not handle: basic-auth credentials, HTTP auth, client secrets, or anything outside the profile’s SQLite stores.

  • Usage: authgrabber <command> [args...]
  • authgrabber --help / -h prints usage.
  • Commands write their primary output to stdout (machine-readable, UTF-8).

Resolve and print the active Firefox profile directory.

authgrabber discover [PROFILE]
  • No arg: the active profile (the one Firefox runs, from profiles.ini [Install*]).
  • PROFILE may be a Firefox profile name (matches Name=), an absolute path, or a browser:profile prefix to select another browser (e.g. vivaldi:Default, chrome:Default, brave:Profile 1).
  • Any supported command accepts the same PROFILE value; Firefox remains the default when no browser prefix is given.

Supported browsers: firefox (default), vivaldi, brave, edge, chromium, chrome. Chromium store reading (cookies/login/localStorage) is implemented by later roadmap phases. discover resolves the profile directory now.

Example: P=$(authgrabber discover)

List saved logins (username/password) from the password manager, decrypted via Firefox’s own NSS library.

authgrabber logins [--values] [PROFILE]
  • Default output: hostname<TAB>username-len<TAB>password-len per login (values are redacted).
  • --values: print the actual decrypted username and password.
  • Decryption uses NSS (libnss3.dylib from the installed Firefox) via dlopen; it handles the key unwrap and SDR decrypt, so no crypto is reimplemented.
  • Requires Firefox to be installed; macOS only for now.
  • No primary password: works automatically.
  • With a primary password set, the tool reports that it is required.

Security: this decrypts real saved passwords, so keep --values output out of logs and shared files; prefer the default redacted form.

Print the Firefox user-agent (UA) string the profile sends on the wire, for passing to obscura’s --user-agent (so the bot presents as the same browser that was authenticated).

authgrabber user-agent [PROFILE]
  • A general.useragent.override pref in the profile’s prefs.js, if set, is returned verbatim (authoritative).
  • Otherwise the default UA is reconstructed from the Firefox version recorded in the profile’s compatibility.ini (LastVersion) plus the host OS.
  • Output: the UA string, on stdout.
  • Example use: obscura fetch <url> --storage-dir <dir> --stealth --user-agent "$(authgrabber user-agent)".
  • For a Chromium profile (vivaldi:Default, …), the UA is reconstructed from the browser’s version (Last Version in the data root) plus the host OS.

List cookies from the active profile (reads a copy of the live DB so it works while Firefox is running).

authgrabber cookies [--values] [PROFILE]
  • Default output: name<TAB>host<TAB>value-length per line.
  • --values: print the full cookie value instead of its length.

List web-storage (localStorage) per origin from the active profile.

authgrabber storage [PROFILE]
  • Output: [<origin>] header, then key = value lines for that origin.
  • Binary (non-UTF-8) values are skipped.

List classified auth tokens from the active profile (cookies + localStorage).

authgrabber tokens [--host <substr>] [PROFILE]
  • Classifies a candidate by key name (access_token, refresh_token, id_token, token), by JWT shape (eyJ...), and (for cookies) by length (>= 128 chars -> opaque session candidate).
  • Decodes JWT payload claims (best-effort): exp, iat, iss, sub, aud, scope, and the user profile claims name, email, picture.
  • --host <substr> restricts to cookies/localStorage whose host or origin contains the substring (e.g. --host conf to focus on one site).
  • --json emits a machine-readable JSON array of tokens (values omitted).
  • --values includes the raw value in the output/JSON (for inspection).
  • Output (text): kind<TAB>store<TAB>origin<TAB>name plus exp=, iat=, scope=, iss=, sub=, aud=, name=, email= for JWT tokens.
  • Value is not printed by default (redacted); noise values are dropped.

Emit a machine-readable session bundle (cookies + classified tokens) for a browser-bot to inject.

authgrabber export-session [--format json|obscura] [--values] [--out <file>] [PROFILE]
  • --format json (default): {cookies: [{name, value, domain, path, secure, httpOnly, sameSite, expires}], tokens: [{type, value, source, origin, expires_at, scope, audience, subject}]}.
  • --format obscura: a JSON array of cookies matching obscura’s cookies.json, ready to drop into a --storage-dir.
  • --out <file>: write to a file with mode 0600 instead of stdout (so session tokens are not world-readable).
  • --values includes the secret values; by default they are null (redacted).

See docs/browser-bot.md for the obscura injection path, and examples/obscura-session.sh for a wrapper.

Run a SQL SELECT against any SQLite database.

authgrabber query <DB> <SQL>
  • Output: result rows, columns separated by <TAB>.
  • Reads the DB together with its -wal sidecar.
  • Errors are reported clearly: OpenFailed, PrepareFailed, database is locked (Firefox running?); retry or close Firefox.

Run the active OAuth authorization-code flow (PKCE + localhost callback):

authgrabber login --auth-url <A> --client-id <ID> --token-url <T> [--scope <S>] [--redirect-uri <URI>] [--values] [--out <file>]

Flow:

  1. Generates a random PKCE verifier/challenge and a state token, and prints the authorization URL and opens it in the default browser.
  2. Binds a one-shot localhost listener (an OS-assigned ephemeral port by default, or the port in an explicit --redirect-uri) to capture the redirect.
  3. Validates the state (constant-time), and prints the authorization code.
  4. Exchanges the code for tokens with a POST to --token-url (grant_type=authorization_code + code_verifier).
  • The token response (and the authorization code) are redacted by default.
  • --values prints them raw, --out <file> writes the token response (mode 0600).
  • --token-url must be https:// (or a loopback http:// for local testing).
  • A non-loopback plaintext --token-url is refused, and a non-HTTPS --auth-url only warns.
  • The ephemeral-port default avoids a fixed, well-known callback port that a local process could squat on to claim the code.
  • Requires --auth-url, --client-id; --token-url triggers the exchange step.
  • Browser command: open (macOS), xdg-open (Linux), start (Windows).
  • 0 success.
  • Non-zero on errors (unrecognized command, missing args, or a command error).
  • zig build - Debug build to zig-out/bin/authgrabber.
  • zig build test - unit tests.
  • zig build cross - cross-compile for x86_64/aarch64 on Windows, Linux, macOS into zig-out/<target>/.
  • just release - optimized ReleaseSmall native build.
  • just release-cross - ReleaseSmall cross-build.
  • just nix-* variants run the same commands via nix develop ..