# dsh-codex-keychain [中文](README.zh.md) An unofficial, independent ChatGPT OAuth provider for [DeepSeek Harness](https://github.com/deepseek-ai/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: ```sh dsh plugin --profile web add dsh-codex-keychain@next dsh web ``` Open **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: ```sh dsh plugin --profile web exec dsh-codex-keychain login --device-code ``` ## CLI ```sh 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 logout ``` `status --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_UNAVAILABLE` on 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_UNAVAILABLE` on Windows:** make sure Windows Credential Manager is available for the current user and that DSH is not running under a different service account. - **`KEYCHAIN_UNAVAILABLE` on 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-codex` provider:** 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: ```sh dsh plugin --profile web exec dsh-codex-keychain logout dsh plugin --profile web remove dsh-codex-keychain ``` ## Supported 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`. ```sh pnpm install pnpm check node scripts/native-keyring-smoke.mjs ``` The 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`](https://github.com/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