dsh-codex-keychain
An unofficial, independent ChatGPT OAuth provider for DeepSeek Harness. It adds the openai-codex model route while keeping the complete OAuth credential in the operating system's native credential store:
- macOS Keychain
- Windows Credential Manager
- Linux Secret Service
There is no OpenAI Platform API key involved, no fallback plaintext credential file, and no reuse of ~/.codex/auth.json.
> [!IMPORTANT] > ChatGPT subscription access and OpenAI Platform API access are different > products. This package connects only to the Codex backend made available to > eligible ChatGPT accounts. It is not affiliated with or endorsed by OpenAI or > DeepSeek.
Status
0.1.0-alpha.1 is a developer preview targeting DeepSeek Harness 0.1.0-rc.6 and @earendil-works/pi-ai 0.82.1.
Install
Install the prebuilt bundle into a DSH profile:
dsh plugin --profile web add dsh-codex-keychain@next
dsh webOpen Settings → OpenAI Codex, choose Sign in with browser, then click Open authorization page and finish the OpenAI authorization. The plugin deliberately does not change the default model; select an openai-codex model from DSH's model picker after signing in.
For headless hosts or when the localhost callback cannot bind:
dsh plugin --profile web exec dsh-codex-keychain login --device-codeCLI
dsh plugin --profile web exec dsh-codex-keychain login
dsh plugin --profile web exec dsh-codex-keychain login --device-code
dsh plugin --profile web exec dsh-codex-keychain status
dsh plugin --profile web exec dsh-codex-keychain status --json
dsh plugin --profile web exec dsh-codex-keychain logoutstatus --json contains only the sign-in state, provider, platform, backend, and—on failure—a stable code and safe message. It never includes tokens, account IDs, or token timestamps.
Security model
The plugin stores a versioned manifest and bounded Base64 chunks entirely as native credential items. The service is io.github.CpfPatrick.dsh-codex-keychain; its root account is a SHA-256 digest of the normalized DSH_HOME, and chunk accounts are derived from that digest. Different Harness homes therefore do not share rotating refresh tokens. Two fixed chunk banks keep updates crash-safe: a new bank is written and verified before the small manifest is switched, then the retired bank is cleared. The bounded items also stay below Windows Credential Manager's per-item limit.
Token refresh and logout use a non-secret cross-process lock under $DSH_HOME/.locks. A refresh failure preserves the previous credential for a later retry or explicit re-login. If the native credential store is missing, locked, or unavailable, the plugin reports KEYCHAIN_UNAVAILABLE and refuses to sign in—there is no silent file fallback.
Web authentication RPC is loopback-only. A remote DSH browser must run the CLI on the DSH host. OAuth URLs and device codes are transient; the plugin does not write them to application logs or persistent storage. The CLI displays them when required for login, so do not share or capture that terminal output.
See [SECURITY.md](SECURITY.md) for reporting and operational guidance.
Troubleshooting
KEYCHAIN_UNAVAILABLEon macOS: unlock the login keychain and allow the
terminal or DSH process to use it. The plugin stays loaded but refuses model requests until secure storage works.
KEYCHAIN_UNAVAILABLEon Windows: make sure Windows Credential Manager
is available for the current user and that DSH is not running under a different service account.
KEYCHAIN_UNAVAILABLEon Linux: run DSH inside a desktop or server
session with a Secret Service provider, such as GNOME Keyring or KWallet, and a working D-Bus session. The plugin never substitutes a file backend or the Linux kernel keyring.
- Browser callback cannot bind: the browser flow uses localhost port 1455.
Stop the process occupying that port, use device-code login, or paste the callback response when the CLI or settings page asks for it.
- Another login is already running: one OAuth flow is allowed at a time
across DSH and CLI processes. Finish or cancel that flow, then retry.
- A process crashed while holding a lock: first confirm that no DSH or
dsh-codex-keychain process for this DSH_HOME is still running. Only then, remove the orphaned $DSH_HOME/.locks/dsh-codex-keychain-openai-codex.lock and/or $DSH_HOME/.locks/dsh-codex-keychain-openai-codex-login.lock. Never remove a live process's lock.
- Duplicate
openai-codexprovider: disable the other Codex/OAuth provider
plugin and restart DSH. Two adapters cannot own the same model route.
- Refresh or authorization failed: run login again. A failed refresh or
incomplete login does not replace the previously stored credential.
- After a DSH upgrade: this alpha is pinned to DSH
0.1.0-rc.6; wait for a
compatibility update or test the newer Developer Preview in an isolated profile before upgrading a working profile.
Remote browsers cannot call the authentication RPC. Run the CLI command on the DSH host instead. To remove the native credential before uninstalling:
dsh plugin --profile web exec dsh-codex-keychain logout
dsh plugin --profile web remove dsh-codex-keychainSupported scope
The alpha includes:
- browser and device-code ChatGPT OAuth
- automatic locked token refresh
- the Codex model catalog and DSH model-picker integration
- DSH-native streaming, reasoning, tool calls, replay, and existing DSH image
attachments/model vision
- a dedicated Web settings page and a headless CLI
It intentionally does not include quota displays, web search, a standalone image-viewing UI, or image generation.
Known alpha limitation: DSH 0.1.0-rc.6 resolves adapter authentication before it creates the per-stream cancellation signal and idle watchdog. Normal model streaming remains cancellable, but a network-stalled token refresh cannot be cancelled by the current request. Do not remove a live process's writer lock; stop that process first if recovery is required.
Development
Requirements: Node.js ^22.19 || >=24 and pnpm 11.7.0.
pnpm install
pnpm check
node scripts/native-keyring-smoke.mjsThe native smoke script sends a disposable OAuth-shaped document larger than 4 KiB through the production chunk store, verifies it, and deletes every item in finally. Unit tests use an injected in-memory driver and never touch the developer's real keychain.
Acknowledgements and clean-room boundary
The DSH community already has OAuth plugins, including Yan-Zero/dsh-codex. This repository was implemented independently against the public DSH and pi-ai interfaces; it does not copy that project's source. The narrow differentiator here is strict, cross-platform native credential storage with no ordinary-file fallback.
License
MIT