Skip to content

Linux: safeStorage falls back to basic_text on non-GNOME/KDE desktops, breaking all credential storage #1875

@raulpineda

Description

@raulpineda

Summary

On Linux desktops where XDG_CURRENT_DESKTOP is not one of the values Chromium recognises for password-store auto-detection (GNOME, KDE, Unity, MATE, Cinnamon, etc.), Chromium picks the basic_text (plaintext) backend for safeStorage. EncryptedAppSecretsStore.assertSecureStorageAvailable() correctly refuses to use basic_text and throws Secure secret storage is unavailable on this system.

Result: every feature that goes through EncryptedAppSecretsStore fails on these systems — even when a fully working Secret Service is running on D-Bus.

Affected setups include Hyprland (Omarchy ships it), Sway, i3, dwm, and any other window manager / compositor that doesn't advertise itself with one of the recognised XDG identifiers. This is a growing slice of the Linux user base.

User-visible impact

Each of the following is broken on affected systems:

  • Sign-in to the Emdash account (auth.emdash.sh) — Account sign-in failed: Error: Secure secret storage is unavailable on this system.
  • GitHub connection — even when gh auth is valid, the token can't be cached. getStatus() re-extracts the CLI token on every poll and the failed setSecret floods the log with Failed to cache CLI token in secure storage.
  • Linear and Plain integrations — setSecret fails on save.
  • SSH password / passphrase storage for the remote-development feature.

Repro

  1. Run Emdash on a host with XDG_CURRENT_DESKTOP=Hyprland (or sway, i3, dwm, ...). Any modern Arch / Omarchy install fits.
  2. The host has a perfectly functional Secret Service: gnome-keyring-daemon --components=pkcs11,secrets is up, org.freedesktop.secrets is owned on the session bus, and secret-tool store / secret-tool lookup round-trips a value successfully.
  3. Launch Emdash. Watch stderr — the Failed to cache CLI token in secure storage stack appears within seconds, repeated for every connection check tick.
  4. Try Settings → Sign in. Sign-in completes the OAuth flow but the final accountCredentialStore.set throws and the session token never persists.

Root cause

Chromium picks the Linux password store from XDG_CURRENT_DESKTOP (os_crypt source). Anything not on its list maps to basic_text. Emdash inherits that default because nothing in src/main/index.ts calls app.commandLine.appendSwitch('password-store', ...). EncryptedAppSecretsStore.assertSecureStorageAvailable() (src/main/core/secrets/encrypted-app-secrets-store.ts:51) then refuses (correctly — you don't want tokens stored in plaintext) and throws.

In other words: the code is doing the right thing, the OS has a working keyring, Chromium's default is just too narrow.

Proposed fix

Add a small Linux-only block in src/main/index.ts, before app.whenReady(), alongside the existing app.commandLine.appendSwitch('ozone-platform-hint', 'auto') call. Roughly:

if (process.platform === 'linux' && !process.argv.some((a) => a.startsWith('--password-store='))) {
  // Chromium's XDG_CURRENT_DESKTOP-based auto-detection doesn't know about
  // Hyprland / sway / i3 / dwm / etc. and falls back to `basic_text`, which
  // EncryptedAppSecretsStore refuses to use. Pick gnome-libsecret if a Secret
  // Service is owning the bus name; otherwise leave the default and let the
  // existing assertSecureStorageAvailable() error explain the problem.
  if (await secretServiceAvailable()) {
    app.commandLine.appendSwitch('password-store', 'gnome-libsecret');
  }
}

Where secretServiceAvailable() does a lightweight check (e.g. dbus-send --session --print-reply --dest=org.freedesktop.DBus /org/freedesktop/DBus org.freedesktop.DBus.NameHasOwner string:org.freedesktop.secrets, or any libdbus binding already pulled in transitively).

For KDE specifically, Chromium already auto-detects kwallet5 / kwallet6 correctly, so we only need the libsecret fallback.

If you'd rather avoid auto-detection entirely, a smaller fix is just to document the --password-store=gnome-libsecret workaround in the README's Linux install section and improve the thrown error to point users at it.

Workaround for users hitting this today

Exec=/path/to/emdash --no-sandbox --password-store=gnome-libsecret %U

(replace gnome-libsecret with kwallet5 / kwallet6 if you use KWallet instead). Once that's set, safeStorage switches to libsecret and all five credential paths work on Hyprland / sway / i3 / dwm.

Happy to send a PR if the auto-detection approach sounds reasonable.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions