Authentication
Log in with browser OAuth for interactive use, or configure an API key for scripts and CI — and switch between them.
The CLI authenticates two ways, mapped to two command namespaces:
- OAuth login —
listenhub auth loginopens your browser, signs you in as a ListenHub user, and stores a refreshable token. Bare commands (listenhub podcast …,listenhub tts …) run as that user. - API key — a
lh_sk_…key authenticates thelistenhub openapi …commands. You set it through an environment variable or a stored config file. This is the mode for servers, scripts, and CI.
The two modes use separate credential files and never interfere with each other. You can have both configured at once.
| OAuth login | API key | |
|---|---|---|
| Set up with | listenhub auth login | listenhub openapi config set-key or LISTENHUB_API_KEY |
| Used by | bare commands (listenhub <cmd>) | listenhub openapi <cmd> |
| Acts as | the signed-in user | the key owner |
| Stored at | ~/.config/listenhub/credentials.json | ~/.config/listenhub/openapi.json (or env var) |
| Best for | interactive work on your own machine | scripts, CI/CD, automation |
Both credential files live under ~/.config/listenhub/. If XDG_CONFIG_HOME is set, the CLI uses $XDG_CONFIG_HOME/listenhub/ instead. Files are written with 0600 permissions (owner read/write only).
OAuth login
Use OAuth when you are working interactively on a machine you control. Nothing long-lived gets baked into a script — the CLI holds a short-lived access token plus a refresh token, and renews automatically.
Log in
listenhub auth loginThis runs a one-time browser flow:
The CLI starts a temporary callback server on a random local port (127.0.0.1) and opens your default browser to the ListenHub login page.
You sign in (and authorize, if prompted) in the browser. ListenHub redirects back to the local callback with an authorization code.
The CLI exchanges the code for tokens, writes them to ~/.config/listenhub/credentials.json, and prints the account it logged in as:
✓ Logged in as Ada LovelaceThe browser flow has a 5-minute timeout. If you do not finish signing in within that window, the command aborts with Login timed out after 5 minutes — rerun listenhub auth login to try again. If the browser does not open on its own, the login URL is printed to the terminal; open it manually.
Check status
listenhub auth status✓ Logged in as Ada Lovelace
Email: ada@example.com
Expires at: 2026-07-01T12:00:00.000Zstatus calls the API with your current token to confirm it is still valid. Add --json for a machine-readable form:
listenhub auth status --json{
"loggedIn": true,
"user": "Ada Lovelace",
"email": "ada@example.com",
"expiresAt": "2026-07-01T12:00:00.000Z"
}If you are not logged in, or the token has expired and cannot be used, status reports that and exits with a non-zero code:
{ "loggedIn": false }Log out
listenhub auth logoutThis revokes your refresh token on the server, then deletes the local credentials.json:
✓ Logged outIf the remote revoke call fails (for example, you are offline), the CLI prints a warning and still clears the local credentials, so the machine is left signed out either way.
Token storage and refresh
credentials.json holds the access token, the refresh token, and an expiresAt timestamp. You do not refresh tokens manually — the CLI renews the access token from the refresh token as needed while you run commands. The file is written atomically (temp file then rename) with 0600 permissions.
Treat credentials.json like any other secret. It grants access to your ListenHub account until you run listenhub auth logout or the refresh token is revoked.
API key
Use an API key when commands run somewhere you cannot complete a browser flow — CI pipelines, cron jobs, servers. API-key auth drives the listenhub openapi … namespace.
Create a key at listenhub.ai/settings/api-keys. Keys start with lh_sk_.
There are two ways to supply the key. The environment variable always takes precedence over the stored file.
Environment variable
Set LISTENHUB_API_KEY in your shell or CI secrets:
export LISTENHUB_API_KEY="lh_sk_your_key_here"
listenhub openapi speakers list --language enThis is the recommended approach for CI/CD: keep the key in your platform's secret store and inject it as an environment variable. Nothing is written to disk.
Stored config
For repeated local use, store the key once:
listenhub openapi config set-keyThe command prompts for the key (input goes to stderr, so it stays out of piped output), validates that it starts with lh_sk_, and writes it to ~/.config/listenhub/openapi.json with 0600 permissions. It then echoes a masked confirmation:
✓ API Key saved (lh_sk_***)A key that does not start with lh_sk_ is rejected before anything is saved:
✗ Invalid API Key format. Must start with "lh_sk_".Inspect and clear
Check which key is active and where it comes from:
listenhub openapi config show✓ API Key configured (source: env)
Key ID: lh_sk_***The source is env when LISTENHUB_API_KEY is set, or file when the key comes from openapi.json. The full key is never printed — only the masked lh_sk_*** prefix. Add --json for scripting:
listenhub openapi config show --json{ "source": "env", "keyId": "lh_sk_live" }If no key is configured, show reports that and exits non-zero.
Remove the stored key (this clears the file only; it does not unset an environment variable):
listenhub openapi config clear✓ API Key clearedAn API key is a long-lived secret tied to your account. Never commit it to source control or paste it into shared logs. Prefer LISTENHUB_API_KEY from a secret store in CI; use stored config only on machines you control.
Which mode should I use?
- Working interactively on your own machine → OAuth login. You avoid keeping a long-lived key on disk, and commands run as you.
- Scripts, CI/CD, servers → API key via
LISTENHUB_API_KEY. It works without a browser and slots into secret managers.
The two are independent. A common setup is OAuth login for day-to-day terminal work plus an API key in CI — both can be configured on the same machine without conflict.
Troubleshooting auth errors
The CLI uses exit code 2 for authentication failures, so scripts can distinguish "not authorized" from other errors (1 = general error, 3 = timeout). Errors are written to stderr.
Common cases and fixes:
| Symptom | Cause | Fix |
|---|---|---|
No API Key configured | Neither LISTENHUB_API_KEY nor a stored key is set | Run listenhub openapi config set-key, or export LISTENHUB_API_KEY |
Invalid API Key format. Must start with "lh_sk_" | The key you entered has the wrong prefix | Copy a fresh key from settings/api-keys; keys start with lh_sk_ |
Not logged in (token expired or invalid) from auth status | OAuth token expired or was revoked | Run listenhub auth login again |
An openapi command fails with an auth error despite config set-key | LISTENHUB_API_KEY is set to a stale/wrong value and overrides the file | unset LISTENHUB_API_KEY (env wins over stored config), or fix the variable |
Login timed out after 5 minutes | Browser flow not completed in time | Rerun listenhub auth login and finish signing in promptly |
To confirm what the CLI currently sees:
listenhub auth status # OAuth session
listenhub openapi config show # API key source (env vs file)