Skip to content

chore(desktop): retire Electron safeStorage as OAuth credential authority #1125

Closed

Description

@Astro-Han

Summary

Retire Electron safeStorage as an authority for OAuth / subscription tokens so desktop, TUI, headless, and other pure-Node surfaces share one credential path.

This is not part of the Electron major upgrade (#1118 / current desktop Electron 43 work). It is a follow-up to the credential-store RFC and the remaining dual-write seam.

Why

  • safeStorage is Electron-only. TUI (maka / maka-agent), headless / Harbor, and any pure-Node caller cannot use it as a store.
  • On macOS dev launches, keychain prompts show Electron asking for Maka Safe Storage whenever the Electron binary path or identity changes (e.g. major upgrades, worktree node_modules). That is expected Keychain ACL behavior, but it is a product smell if the desktop copy is still treated as primary.
  • SECURITY.md already treats the OS user account + 0700/0600 filesystem controls as the load-bearing credential-at-rest boundary. At-rest encryption via safeStorage is a secondary desktop copy, not a cross-surface authority.

Current state (as of 2026-07)

Surface What exists today
Provider API keys Pure-Node CredentialStore → workspace credentials.json (post-#32). Desktop keeps a one-time migration importer off legacy safeStorage encoding.
Claude / Codex OAuth Dual-write: desktop still persists a safeStorage-encrypted token file under userData; also best-effort exports plaintext oauth_token into credentials.json for the pure-Node runtime.
Cursor / Antigravity Preview integrations; still largely desktop + safeStorage token files.
TUI / headless Consume credentials.json / CredentialStore. They do not decrypt desktop safeStorage blobs.

So: using an already-exported OAuth token in TUI/headless can work; the login / refresh / desktop authority path still depends on Electron safeStorage for the desktop-side copy.

Goal

  1. Single source of truth for OAuth secrets: @maka/storage CredentialStore (file store by default; optional future credential_provider for keychain / 1Password / Vault).
  2. Desktop OAuth services (Claude, Codex, and any remaining preview providers that become real) read/write that store for the runtime-visible secret; stop treating safeStorage-encrypted userData files as authority.
  3. safeStorage role → migration-only (or delete after a deprecation window): decrypt legacy desktop token files once into CredentialStore, then stop writing them.
  4. Login UX may still use Electron (system browser / loopback) on desktop; TUI/headless need documented paths: reuse exported tokens, device-code / CLI login where applicable, or env / credential_provider — without requiring a running Electron app to decrypt secrets.
  5. Update SECURITY.md / README credential sections so they describe one model, not dual-write.

Non-goals

Acceptance sketch

  • No production OAuth path requires safeStorage.isEncryptionAvailable() to save or load the runtime-usable token.
  • After a desktop OAuth login (or migration), TUI and headless can authenticate with the same account from credentials.json / CredentialStore without touching Electron.
  • Legacy safeStorage token files either migrate automatically on desktop start or are documented as dead with a one-shot importer.
  • Docs (SECURITY.md, product README credential bullets) match the single-store model.
  • Contract tests cover: dual-write removed or reduced to explicit migrate-once; fail-closed behavior when the pure-Node store cannot write.

References

Proposal for sequencing

Keep this issue independent of Electron upgrades. Prefer a small PR series:

  1. Docs + inventory of remaining safeStorage call sites and what each secret is for
  2. Make CredentialStore the write path for Claude/Codex runtime tokens; keep encrypted desktop file only if still needed for a short migrate window
  3. Desktop startup: import-once from legacy encrypted files, then stop writing them
  4. Remove safeStorage from OAuth hot paths; leave or delete the API-key migration helper as appropriate
  5. Cursor/Antigravity when they leave preview: never introduce a new safeStorage authority

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions