Skip to content

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 details line 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 login or jsm 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=1 was 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, including Credential Storage
  • /help/cli — CLI installation guide
  • /account/api-keys — generate and revoke API keys