Skip to content

[Feature]: add opt-in authless Codex Desktop routing mode #1107

Closed

Description

@majia3592

Area

Codex Desktop integration / authentication / Codex config injection

Goal

Provide an explicit opt-in mode that lets Codex Desktop use OpenCodex without requiring a ChatGPT OAuth login when the selected OpenCodex workflow does not need ChatGPT credentials.

This must remain an OpenCodex-scoped integration mode, not a global Codex authentication bypass.

Confirmed behavior

The original diagnostic established an important upstream fact:

model_provider = "opencodex"

[model_providers.opencodex]
name = "OpenCodex Proxy"
base_url = "http://127.0.0.1:10100/v1"
wire_api = "responses"
requires_openai_auth = false

With OpenCodex stopped so it could not reconcile the file, Codex Desktop:

  • skipped the ChatGPT OAuth login screen;
  • entered the normal Desktop UI;
  • routed a conversation through the local OpenCodex proxy.

So Codex Desktop does honor requires_openai_auth = false for a dedicated custom provider.

Current OpenCodex architecture

The implementation architecture changed after the original report.

Current dev uses Design B for normal loopback installs:

openai_base_url = "http://127.0.0.1:<port>/v1"

instead of permanently installing:

model_provider = "opencodex"
[model_providers.opencodex]

The reason is deliberate: loopback routing keeps Codex on its built-in openai provider and avoids provider retagging/history remapping.

During normal loopback reconciliation, OpenCodex removes the dedicated opencodex provider table and injects openai_base_url. This was observed directly in the full-flow test attached to this issue and is also documented in src/codex/inject.ts.

Non-loopback binds still need the dedicated provider-table path because the built-in provider cannot carry the OpenCodex admission header in the same way.

Therefore the original implementation prescription, "always write requires_openai_auth = false into the managed [model_providers.opencodex] table", is stale for the normal loopback path.

Remaining problem

There is still no supported OpenCodex setting for this workflow.

Users can prove authless Desktop behavior manually, but ocx start reconciles the configuration back to the normal openai_base_url shape. A manual edit is therefore not durable.

The feature now needs a solution that is compatible with the current injection architecture rather than reviving the old provider table unconditionally.

Required behavior

  1. Existing installs keep their current authenticated/default behavior unless the user explicitly opts in.
  2. The setting is durable across ocx start, restart, sync, ensure, and normal config reconciliation.
  3. The option affects only Codex Desktop/OpenCodex routing behavior. It must not disable authentication globally.
  4. Loopback OpenCodex admission remains safe. Authless Codex Desktop login must not be confused with exposing a non-loopback OpenCodex listener without admission authentication.
  5. CLI behavior remains unchanged unless explicitly designed otherwise.
  6. Disabling the option restores the normal supported OpenCodex injection path.

Implementation boundary

The implementation must first choose and prove a Codex-supported mechanism for the current loopback architecture.

Acceptable directions include:

A. Dedicated-provider mode only when authless Desktop is enabled

OpenCodex may intentionally switch the Codex config to a dedicated opencodex provider only for this opt-in mode, with:

requires_openai_auth = false

If this direction is used, it must solve the additional behavior found in the full-flow test: the Desktop model selector was empty under the manually installed custom provider even though direct conversation routing worked.

The opt-in must therefore be a complete supported mode, not merely a login-screen bypass that leaves model selection degraded.

B. A verified Codex-supported authless control compatible with openai_base_url

If current Codex exposes a supported way to keep the built-in openai routing shape while declaring that Desktop login is unnecessary, OpenCodex may use that instead.

Do not invent or guess such a field. It must be verified against the current Codex configuration/app-server contract.

Non-loopback safety

Current non-loopback OpenCodex routing uses the dedicated provider table so Codex can send the OpenCodex admission credential.

Any authless Desktop option must preserve that data-plane admission boundary. It must never mean:

requires_openai_auth = false
=> disable OpenCodex network authentication

Those are separate authentication layers.

Suggested management surface

The exact public key can follow existing configuration conventions, for example conceptually:

{
  "codex": {
    "desktop": {
      "authMode": "native"
    }
  }
}

or:

{
  "codex": {
    "desktop": {
      "requiresOpenAIAuth": false
    }
  }
}

The public contract matters more than the exact field name:

default -> current behavior
authless opt-in -> supported Desktop routing mode without ChatGPT login

Acceptance criteria

  • Codex Desktop is confirmed to honor requires_openai_auth = false for a dedicated custom provider.
  • A conversation is confirmed to route through OpenCodex in that diagnostic mode.
  • Current loopback OpenCodex injection is known to use openai_base_url rather than the old dedicated-provider table.
  • A first-class OpenCodex authless Desktop setting exists and defaults off.
  • The implementation is compatible with the current loopback injection architecture.
  • ocx start, restart, sync, and reconciliation preserve the opt-in.
  • Desktop starts without the ChatGPT OAuth gate when the option is enabled.
  • Model selection/catalog behavior remains usable in the supported authless mode.
  • Requests continue to route through OpenCodex.
  • Non-loopback OpenCodex admission authentication is not weakened.
  • Disabling the option restores normal behavior.
  • Existing CLI behavior remains unchanged.
  • Tests cover default mode, authless loopback mode, reconciliation, disable/restore, and non-loopback safety.

Out of scope

  • globally disabling Codex authentication;
  • making non-loopback OpenCodex listeners unauthenticated;
  • treating the empty custom-provider model selector as acceptable product behavior;
  • unrelated Desktop model-default or catalog bugs unless they block the supported authless mode.

Activity

  1. github-actions commented on Aug 6, 2026

    @github-actions
    Contributor

    Automated translation bookkeeping — detected language: English.

  2. Ingwannu commented on Aug 6, 2026

    @Ingwannu
    Owner

    There is a concrete OpenCodex-controlled boundary here, but I do not think a global auth bypass is safe to implement from the report alone.

    Current dev deliberately writes requires_openai_auth = true in the managed [model_providers.opencodex] table (src/codex/inject.ts:195-215). Current Codex app-server/TUI source does honor requires_openai_auth = false for a custom provider: it skips the login screen and reports requires_openai_auth: false from account status. Therefore this is not inherently limited to the built-in deepseek provider, and OpenCodex can influence the gate when it owns the dedicated-provider table.

    The important distinction is whether the failure is caused by OpenCodex rewriting the managed table back to true, or by a separate Codex Desktop frontend restriction after app-server has already reported that auth is not required.

    Could you please test this exact diagnostic after stopping OpenCodex so it cannot rewrite the file during the test:

    model_provider = "opencodex"
    
    [model_providers.opencodex]
    name = "OpenCodex Proxy"
    base_url = "http://127.0.0.1:10100/v1"
    wire_api = "responses"
    requires_openai_auth = false

    Then restart only Codex Desktop and report whether the login gate is skipped. Please also include the hostname value from the OpenCodex config (loopback vs 0.0.0.0/LAN matters because OpenCodex uses different injection shapes).

    If that works, the maintainable scope is an explicit opt-in on the managed dedicated-provider injection while keeping the current default for users who depend on ChatGPT account-gated surfaces. If it still fails, the remaining gate is in the Desktop client and should be tracked upstream rather than worked around by guessing in the proxy. I am leaving this open for that result.

  3. majia3592 commented on Aug 7, 2026

    @majia3592
    Author

    Diagnostic test result

    Tested the exact config you suggested. Login gate was skipped successfully.

    Setup

    Stopped OpenCodex, then manually edited ~/.codex/config.toml (without starting ocx):

    model_provider = "opencodex"
    
    [model_providers.opencodex]
    name = "OpenCodex Proxy"
    base_url = "http://127.0.0.1:10100/v1"
    wire_api = "responses"
    requires_openai_auth = false

    Then restarted only Codex Desktop (no ocx start).

    Result

    • Codex Desktop launched directly into the main UI — no OAuth login page
    • Bottom-left corner shows "opencodex" status indicator
    • Model list displays GPT models (5.6 Sol / Terra / Luna)
    • Previously, with model_provider = "opencodex" and the default requires_openai_auth = true, the login gate always appeared

    Hostname

    OpenCodex config (~/.opencodex/config.json) has no explicit hostname field. Default is 127.0.0.1 (loopback).

    Implication

    This confirms that requires_openai_auth = false in the managed [model_providers.opencodex] table is sufficient to bypass the Desktop OAuth gate. The maintainable path would be an explicit opt-in flag in OpenCodex injection — when the user sets a custom provider that does not need ChatGPT credentials, OpenCodex writes requires_openai_auth = false instead of the current true default.


    Note: This comment was drafted with AI assistance.

  4. majia3592 commented on Aug 7, 2026

    @majia3592
    Author

    Full flow test — additional findings

    Continued testing beyond the initial requires_openai_auth = false diagnostic.

    What we did

    1. Set model_provider = "opencodex" + requires_openai_auth = false in config.toml
    2. Set model = "deepseek/deepseek-v4-flash" (proxy-compatible format)
    3. Started Desktop — login gate skipped, bottom-left shows "opencodex" ✅
    4. Model selector was empty (no models listed)
    5. Started ocx start — models injected into catalog (13 models in models.json)
    6. Restarted Desktop — model selector still empty, but conversation works
    7. Sent "hello" — received a response through the proxy

    What we observed

    • ocx start modifies config.toml: removes model_provider, removes requires_openai_auth, removes [model_providers.opencodex] section, injects openai_base_url. We had to re-add model_provider and requires_openai_auth after ocx start.
    • Desktop reads config at startup and does not re-read while running, so ocx start modifications do not affect an already-running Desktop instance.
    • Model selector is empty when model_provider = "opencodex" — Desktop does not load models from model_catalog_json for custom providers.
    • Setting model in config.toml works — Desktop uses the specified model for conversations even though the selector is empty.
    • Conversation flows through the proxy — requests go to localhost:10100 and get routed to the configured backend.

    Current state

    Config restored to model_provider = "deepseek" (original). Proxy stopped.


    Note: This comment was drafted with AI assistance.

  5. majia3592 commented on Aug 8, 2026

    @majia3592
    Author

    Follow-up: gpt-5.6-terra 404 on NEW conversations (Aug 8) — interception list gap

    Current working setup on our side (pure China network, no chatgpt.com):

    • forced_login_method = "api" + preferred_auth_method = "apikey" + dummy API key (key validation goes through the proxy, not OpenAI) — Desktop starts without the OAuth gate.
    • config.toml: model = "opencode-go/deepseek-v4-flash", openai_base_url = "http://127.0.0.1:10100/v1" (auto-injected by ocx).

    Problem

    When starting a new conversation in Desktop, the client requests the hard-coded default model gpt-5.6-terra (not the model line from config.toml). The proxy rejects it with:

    404 "Model gpt-5.6-terra requires the canonical openai provider. Run: ocx provider add openai && ocx sync && ocx restart"
    

    Existing conversations keep working (per-conversation model opencode-go/deepseek-v4-flash is remembered), but every new conversation 404s in a loop. Meanwhile the proxy still returns 200 for the old conversation.

    Root cause (proxy side)

    shadowCallIntercept only matches gpt-5.4-mini / gpt-5.6-luna by default (DEFAULT_SHADOW_SOURCE_MODELS in src/lib/shadow-call.ts). gpt-5.6-terra is the main-conversation default model, not a helper call, so it is never rewritten — by design. But that means Desktop's hard-coded new-chat default has neither an interception path nor a canonical provider → 404.

    Suggestions

    1. Include gpt-5.6-terra (or make the shadow-call source list prefix-configurable) so Desktop's new-chat default is rewritten instead of 404ing. Alternatively add a generic "unknown bare native slug → user-configured fallback model" rule in the router.
    2. Related: when forced_login_method=api is set, it would help if Desktop respected the model line for new conversations instead of falling back to its built-in default.
    3. Minor: ocx start still strips the model line (and previously model_provider / requires_openai_auth) from config.toml on every proxy restart — a preserve-list for user-managed keys would eliminate the manual restore step.

    Environment: Windows 11, Codex Desktop (MSIX), opencodex v2.10.0, loopback 127.0.0.1:10100.

  6. majia3592 commented on Aug 8, 2026

    @majia3592
    Author

    Complete reproducible workflow: one-time login with internet, then stable China-network usage (our results)

    Sharing the full working setup so other users in blocked networks can replicate it. This is the production configuration we have been running — every step below is tested on Windows 11 + Codex Desktop (MSIX) + opencodex v2.10.0.

    Phase 1 — One-time preparation (with internet, ~10 min)

    1. Install Codex Desktop (MSIX) and opencodex (use npmmirror registry inside China).
    2. (Optional but recommended) Log in to ChatGPT once via OAuth — Desktop then shows routed models in the selector when internet is available. Not strictly required.
    3. Configure ~/.opencodex/config.json:
    {
      "port": 10100,
      "defaultProvider": "opencode-go",
      "providers": {
        "opencode-go": { "adapter": "openai-chat", "baseUrl": "https://opencode.ai/zen/go/v1", "authMode": "key", "liveModels": true },
        "deepseek":    { "adapter": "openai-responses", "baseUrl": "https://api.deepseek.com", "authMode": "key" },
        "xiaomi":      { "adapter": "anthropic", "baseUrl": "https://api.xiaomimimo.com/anthropic", "authMode": "key" }
      },
      "shadowCallIntercept": {
        "enabled": true,
        "model": "opencode-go/mimo-v2.5",
        "sourceModels": ["gpt-5.4-mini", "gpt-5.6-luna", "gpt-5.6-terra"]
      }
    }
    1. Set user env var (critical, prevents 502 from system proxy hijacking loopback):
      setx NO_PROXY "127.0.0.1,localhost"

    Phase 2 — Switch to pure China network (daily driver)

    1. ocx start, verify curl -s --noproxy "*" http://127.0.0.1:10100/healthz.
    2. Key lines in ~/.codex/config.toml:
      • model = "opencode-go/deepseek-v4-flash"
      • preferred_auth_method = "apikey" + forced_login_method = "api" ← bypasses the Desktop OAuth gate
      • openai_base_url = "http://127.0.0.1:10100/v1" (auto-injected)
    3. In Desktop: switch to API key mode, enter a dummy key (e.g. sk-test123) — validation goes through the proxy, which does not check it. No chatgpt.com involved.
    4. Auto-start: copy the launcher VBS to the Startup folder (wscript → cmd watchdog loop, auto-restarts the proxy).

    Result (verified)

    • All requests 200, routed to opencode-go/deepseek-v4-flash (main) or mimo-v2.5 (shadow/helper/default-new-chat).
    • New conversations default model gpt-5.6-terra is intercepted by the sourceModels list → no more 404 loop.
    • Model switching = edit the model line + restart Desktop (model selector is empty in API-key mode; that is expected).
    • After every proxy restart, ocx start strips the model line from config.toml — restore it (a preserve-list for user-managed keys would remove this manual step).

    Hints for the maintainer

    The generic fix that would benefit all users: route unknown bare native slugs (like gpt-5.6-terra when the catalog does not contain it) to a user-configured fallback model instead of failing with requires the canonical openai provider 404 — and/or include gpt-5.6-terra in the default shadow-call source list.

  7. Ingwannu commented on Aug 9, 2026

    @Ingwannu
    Owner

    The diagnostic result confirms the important boundary: OpenCodex can control the Desktop login gate through the managed provider table, and requires_openai_auth = false works when the proxy is not rewriting that table.\n\nThe safe implementation scope is therefore an explicit opt-in dedicated-provider mode that preserves the managed model_provider table and user-selected model while setting requires_openai_auth = false. I would not make unknown native slugs or gpt-5.6-terra silently route through shadowCallIntercept by default; helper-call interception and the main new-chat model are different semantics, and a global fallback can hide configuration errors.\n\nThe empty selector under a custom provider is still a Desktop/upstream limitation. Because this changes authentication and product behavior rather than fixing a narrow adapter bug, I am leaving the implementation decision to @lidge-jun. The reported manual configuration is useful as a diagnostic workaround, but we should not document dummy-key acceptance as the final supported flow.

  8. changed the title [-]Skip OAuth check for custom providers in Desktop (China/corporate network support)[/-] [+][Feature]: add opt-in authless Codex Desktop mode for OpenCodex provider[/+] on Aug 9, 2026
  9. changed the title [-][Feature]: add opt-in authless Codex Desktop mode for OpenCodex provider[/-] [+][Feature]: add opt-in authless Codex Desktop routing mode[/+] on Aug 11, 2026
  10. lidge-jun commented on Aug 19, 2026

    @lidge-jun
    Owner

    리뷰 · 우선순위 71 / 80

    현재 dev의 루프백 주입은 Design B입니다. src/codex/inject.ts는 전용 [model_providers.opencodex]를 상시 설치하지 않고, 내장 openai 프로바이더에 openai_base_url = "http://127.0.0.1:<port>/v1"를 씁니다. 전용 테이블이 남을 때 requires_openai_auth = true가 명시됩니다. 그래서 이슈의 예전 처방(“항상 전용 테이블에 false를 써라”)은 현재 아키텍처와 어긋납니다.

    이슈가 원하는 것은 ChatGPT OAuth가 필요 없는 워크플로를 위한 명시적 옵트인입니다. 수동으로 model_provider = "opencodex"와 requires_openai_auth = false를 넣으면 Desktop이 로그인 게이트를 건너뛰는 것은 재현됐습니다. 그러나 ocx start가 설정을 다시 openai_base_url 형태로 맞추면 그 편집은 사라집니다. 지속 가능한 OpenCodex 설정이 없습니다.

    네이티브 신뢰성이 점수 이유입니다. 전역 인증 우회는 안 됩니다. 루프백 기본 경로를 전용 테이블로 되돌리면 히스토리 리태깅/프로바이더 재매핑이 다시 생기고, 비루프백 바인딩은 입장 헤더 때문에 전용 테이블이 필요합니다. Windows + 차단된 chatgpt.com 환경의 실사용 코멘트가 이 공백을 보여 줍니다. 더미 API 키와 forced_login_method = "api"는 우회이지 제품 계약이 아닙니다.

    서비스/자동시작에서도 같은 조정자가 파일을 다시 씁니다. 옵트인 플래그가 조정 대상이 아니면 ocx start와 서비스 재기동이 로그인 게이트를 되돌립니다. 위생적으로는 OpenCodex 범위 모드여야 하고, 사용자 소유 openai_base_url을 덮어쓰면 안 됩니다.

    해결방안은 기본 루프백 경로를 유지한 채, 옵트인일 때만 전용 opencodex 프로바이더 테이블을 보존하고 requires_openai_auth = false를 쓰며 사용자 선택 모델을 유지하는 것입니다. 기본값은 지금과 같아야 합니다. 패치는 추측하지 않으며, 현재 트리에 authless 설정 키는 없습니다.

    이 댓글은 grok-bot이 작성했습니다

  11. lidge-jun commented on Sep 1, 2026

    @lidge-jun
    Owner

    Landed on dev via #3207 (squash 4a382beed).

    What shipped:

    • codexDesktopAuthless: true in config.json, or ocx system settings --desktop-authless on, or PUT /api/settings. Default off keeps today's loopback injection byte-for-byte.
    • On a loopback bind the injector writes model_provider = "opencodex" plus [model_providers.opencodex] with requires_openai_auth = false and no env_key, so Desktop opens without the ChatGPT login and routes through the proxy. The setting is reconciled by ocx start, restart, sync, and ensure; the fallback profile mirrors the form.
    • Turning it off restores the root openai_base_url form on the next sync; ocx restore strips it like any injected routing.
    • Non-loopback binds ignore the switch: requires_openai_auth = true and the env_key admission credential are unchanged, so the data-plane admission boundary is untouched.

    Known limits, documented in the guide: ChatGPT-gated Desktop chrome (account, usage, Fast) stays dark in this mode, and Desktop releases that filter the picker against a native-only allowlist may show an empty or Custom picker (upstream openai/codex#19694); requests still use the configured model and model = "<provider>/<id>" in config.toml is the workaround. OpenCodex has no hook into that renderer allowlist, so the empty picker is not something this repository can fix.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    account-poolOAuth, credentials, Codex pool, quota, failover, plansenhancementNew feature or request

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions