Skip to content

Store third-party provider API keys in the OS keychain (currently plaintext in config.json) #1221

Description

@iifuaann-zhu

What are you trying to accomplish?

When using opencodex with API-key providers such as DeepSeek, I'd like the raw key material to not sit in plaintext JSON on disk.

What prevents this today?

providers.<name>.apiKey and apiKeyPool are persisted verbatim in ~/.opencodex/config.json (and in config backups). File permissions are hardened to 0600 and atomic writes scrub temp-file residuals, but the key material is still recoverable from the config file, backups, or any accidental copy or screenshot — unlike native GPT main profiles, which PR #863 already stores encrypted (no plaintext fallback).

What should OpenCodex do?

Provide an opt-in, OS-keychain-backed credential store for provider API keys — e.g. macOS Keychain (security find-generic-password), Windows Credential Manager/DPAPI, Linux libsecret — enabled by a per-provider flag such as credentialStore: "keychain". When the keychain is unavailable or the user opts out, fall back to the current 0600-permission config-file behavior.

Example usage or interface

ocx config set providers.deepseek.credentialStore keychain

The key would be written to the OS keychain, and config.json would hold only a reference (e.g. keychain:deepseek) instead of the raw key.

Alternatives or workarounds

Env-var references already work today: set providers.deepseek.apiKey to ${DEEPSEEK_API_KEY} and export the variable in the service environment (resolved at routing time). This is the current mitigation; keychain support would remove the need to manage service env vars and would also cover apiKeyPool entries.

Additional context

Verified on opencodex 2.10.2 (macOS). Native profiles already use an encrypted store (PR #863), so this extends an existing pattern to key-auth providers.

Checks

  • I searched existing issues and documentation.
  • This request describes a concrete OpenCodex workflow rather than merely naming a desired technology.
  • I removed secrets and personal data.

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions