Help · CLI · Credentials
CLI Credentials Guide
Where the jsm CLI stores credentials, how to silence the passphrase prompt, and how to wire up the platform-native secret store on macOS, Windows, and Linux.
CLI Credentials: Keyring, Passphrase, and Headless Setups
When you sign in with jsm login, the CLI completes Google OAuth in your
browser and then needs somewhere durable to put the resulting access and
refresh tokens. This page covers where those tokens land, what to do when
the CLI prompts you for a passphrase, and how to wire up the platform-native
secret store on each OS so you stop getting prompted at all.
Why the CLI cares about credential storage
The refresh token the CLI receives after jsm login is a bearer credential.
Anyone who reads it off your disk can use it to download premium content as
you until it expires. The CLI deliberately avoids ever writing it in
plaintext: the default path is to hand it to the operating system's secret
store (Keychain on macOS, Credential Manager on Windows, GNOME Keyring or
KWallet on Linux), and the fallback path is an AES-256-GCM-encrypted file at
~/.config/jsm/credentials.json with a passphrase you set on first save.
You can tell which path you're on by running jsm doctor. The
Credential Storage check reports one of:
- OS keyring — you're on the recommended default. No prompts.
- Encrypted file (interactive passphrase) — the keyring wasn't usable,
so the CLI fell back to the file and prompts for a passphrase on each
load. The
detailsline explains why the keyring isn't available (volatile backend, not installed, daemon not running, etc.). - Encrypted file (env passphrase) — same file fallback, but you've opted into reading the passphrase from environment variables so the CLI doesn't prompt.
- No credentials stored — fresh machine; run
jsm loginorjsm auth set-key.
macOS — Keychain
Keychain works out of the box. The first time the CLI writes credentials,
macOS prompts once to grant jsm access. After that, no prompts.
If you ever see a passphrase prompt on macOS, that means Keychain access was
denied or revoked. Open Keychain Access, search for jsm, and either
re-allow the entry or delete it and run jsm login again.
Windows — Credential Manager
Credential Manager works out of the box. Stored credentials live under
Control Panel → User Accounts → Credential Manager → Windows Credentials
with the target name jsm. Deleting that entry and re-running jsm login
re-creates it.
Linux — GNOME Keyring (Fedora, Ubuntu, Debian)
GNOME Keyring is the most common Linux backend. It's a daemon (gnome-keyring-daemon)
that exposes the Secret Service D-Bus API the CLI talks to via the
secret-service Rust binding. If you're in a normal GNOME desktop session
(including GNOME Classic), the daemon starts automatically when you log in
and the CLI uses it without you doing anything.
If jsm doctor reports the encrypted-file fallback on Linux, install
GNOME Keyring and confirm the daemon is running:
# Fedora / RHEL
sudo dnf install gnome-keyring libsecret
# Ubuntu / Debian
sudo apt install gnome-keyring libsecret-1-0
# Arch / Manjaro
sudo pacman -S gnome-keyring libsecret
In a desktop session, the daemon should already be running. To verify:
pgrep -af gnome-keyring-daemon
busctl --user list | grep -i secret
For a non-GNOME desktop or an SSH session that needs the keyring (rare but sometimes useful), start the daemon manually and export the variables it prints:
eval "$(gnome-keyring-daemon --start --components=secrets)"
export GNOME_KEYRING_CONTROL SSH_AUTH_SOCK
Once the daemon is reachable, run jsm logout && jsm login so the CLI
writes fresh credentials into the keyring instead of the file fallback.
The passphrase prompts should disappear.
Linux — KWallet (KDE)
KWallet exposes the same Secret Service API used by GNOME Keyring, so the CLI talks to it through the same Rust binding without any extra configuration. Install with:
# Fedora / KDE Plasma
sudo dnf install kwalletmanager5
# Ubuntu / Kubuntu
sudo apt install kwalletmanager
After install, the wallet daemon (kwalletd5) starts with your session.
The wallet itself is unlocked with your KDE login password.
Linux — kernel keyutils (server-side @u keyring)
Some Linux distributions present the kernel keyutils keyring as the
default backend. It's volatile (entries die at reboot), which is exactly
the wrong shape for an access token you want to persist across login
sessions, so the CLI deliberately treats it as Unsupported and falls
through to the encrypted file path. jsm doctor will spell this out:
Credential Storage: Encrypted file (interactive passphrase)
OS keyring not used: Detected a volatile (UntilReboot) keyring backend...
This is intentional, not a bug. Install GNOME Keyring or KWallet as above to get a real backend.
Headless servers — env-passphrase opt-in
On a server with no desktop session (no GNOME Keyring, no KWallet), the keyring path isn't available at all. You have two options:
Option A — Use an API key instead of OAuth
API keys are stored under the same encryption, but they're per-user identity tokens you mint from the website and revoke from the website, which is a better fit for unattended use:
# Generate a key at /account/api-keys
jsm auth set-key jsm_xxxxxxxxxxxxxxxxxxxxxxxx
This still triggers a passphrase prompt on first save, but you only set it once on the machine.
Option B — Read the passphrase from environment variables
Add both of these to your shell rc (~/.bashrc, ~/.zshrc, systemd unit
Environment=, etc.) and the CLI will stop prompting:
export JSM_ALLOW_ENV_PASSPHRASE=1
export JSM_CREDENTIALS_PASSPHRASE='<your passphrase>'
Both variables are required. JSM_CREDENTIALS_PASSPHRASE alone is
intentionally ignored — we want the env-var path to be an explicit opt-in,
not a default that erodes the on-disk encryption guarantee silently. With
both set, the CLI prints a one-line notice to stderr on first use so you
can tell the env-var path is active:
jsm: using credential passphrase from JSM_CREDENTIALS_PASSPHRASE (JSM_ALLOW_ENV_PASSPHRASE is set).
To suppress that line in fully unattended scripts, also set JSM_QUIET=1.
If you genuinely want no keyring path at all (e.g. you're testing the
file fallback or your distro ships a broken keyring backend), set
JSM_DISABLE_KEYRING=1 so the CLI doesn't even try.
Troubleshooting
"Enter passphrase for CLI credentials:" on every command
Run jsm doctor. If Credential Storage shows "Encrypted file
(interactive passphrase)", the keyring isn't being used. The details
line tells you why — that's your starting point. Most often it's one of:
- GNOME Keyring not installed → install it (commands above).
- GNOME Keyring installed but daemon not running → check
pgrep -af gnome-keyring-daemon; if empty, you're not in a desktop session. JSM_DISABLE_KEYRING=1was set → unset it and re-run.- You're on the volatile kernel keyring → install GNOME Keyring; the CLI intentionally won't use the volatile backend.
"Cannot prompt for passphrase in non-interactive environment"
You're running jsm over SSH or under a process that has no TTY, and the
keyring is unavailable. Set JSM_ALLOW_ENV_PASSPHRASE=1 and
JSM_CREDENTIALS_PASSPHRASE as above, or switch to API-key auth.
Wiped Keychain / Credential Manager and now things are weird
jsm logout then jsm login from a regular terminal session. The CLI
will re-acquire credentials and store them into whichever backend is
healthy.
I want to start over
jsm logout
rm -f ~/.config/jsm/credentials.json
jsm login
jsm logout clears the keyring entries; the rm clears the encrypted
file. jsm login then starts a fresh OAuth flow.
See also
jsm doctor— top-line health check, includingCredential Storage/help/cli— CLI installation guide/account/api-keys— generate and revoke API keys