Skip to content

[Feature]: add least-privilege GET /v1/catalog for remote Codex clients #809

Description

@nbsp1221

Area

Authentication / catalog distribution / remote clients

Goal

Allow a remote Codex client to download OpenCodex's generated Codex model catalog using the same least-privilege credential class it already uses for inference.

The client must not need the management credential merely to obtain model metadata.

This is primarily needed for centrally hosted and multi-machine deployments such as #95.

Current state

OpenCodex already exposes the generated catalog through:

GET /api/catalog

but that endpoint is intentionally part of the management plane.

The management credential can also access sensitive administrative operations such as:

  • provider configuration;
  • OAuth/account management;
  • server settings;
  • management mutations;
  • proxy shutdown.

Giving that credential to every remote inference client violates least privilege.

The accepted implementation direction is therefore not to weaken admission for /api/catalog.

Instead, add a separate read-only data-plane catalog route.

Accepted route

Add:

GET /v1/catalog

with optional:

HEAD /v1/catalog

using the existing data-plane authentication boundary.

A client that can already call:

POST /v1/responses

should be able to fetch:

GET /v1/catalog

using the same data-plane credential.

That credential must continue to receive 401 / denial for management routes.

Security boundary

The /api/* management namespace remains unchanged.

Do not add a special case such as:

data-plane token
    -> allowed through /api/catalog

The desired separation is:

Data plane
  /v1/responses
  /v1/chat/completions
  /v1/messages
  /v1/models
  /v1/catalog

Management plane
  /api/*

A data-plane credential that can read /v1/catalog must still be unable to access, for example:

GET  /api/config
GET  /api/providers
POST /api/oauth/login
POST /api/codex-auth/login
POST /api/stop

or any other management-only route.

Payload contract

GET /v1/catalog should reuse the same authoritative generated catalog payload and sanitization/redaction rules as:

GET /api/catalog

Do not create an independently generated second catalog.

The two routes should expose equivalent catalog content subject only to differences that are intentionally specific to their transport/auth surface.

The data-plane response must not expose:

  • provider API keys;
  • OAuth credentials;
  • management tokens;
  • account identifiers;
  • raw provider configuration;
  • internal filesystem paths;
  • other management-only state.

Method restrictions

The data-plane catalog surface is read-only.

Allowed:

GET
HEAD

Not allowed:

POST
PUT
PATCH
DELETE

No catalog mutation API should be introduced under /v1.

Response behavior

Preserve the useful catalog-distribution metadata already provided by the management route where applicable, including:

  • bounded response size;
  • content type;
  • cache-related headers;
  • version/skew metadata;
  • deterministic errors when the catalog cannot be materialized.

If the existing management route exposes a Codex-version header, preserve that contract where the corresponding information is available.

Do not fabricate a version when the proxy has no authoritative runtime version.

Remote-client workflow

A centrally hosted OpenCodex deployment should support:

curl -fsS \
  -H "x-opencodex-api-key: $DATA_PLANE_KEY" \
  https://proxy.example.com/v1/catalog \
  > "${CODEX_HOME:-$HOME/.codex}/opencodex-catalog.json"

The same credential can then be used for inference:

curl -fsS \
  -H "x-opencodex-api-key: $DATA_PLANE_KEY" \
  https://proxy.example.com/v1/responses \
  ...

while the management credential remains only on the operator's trusted machine.

Admission tests

Regression coverage must prove both halves of the boundary.

Positive

A valid data-plane credential can:

GET  /v1/catalog
HEAD /v1/catalog

and receives the expected generated catalog metadata.

Negative

The same credential cannot access:

/api/*

including representative reads and mutations.

Also verify that:

  • missing credentials fail when data-plane auth is required;
  • invalid credentials fail;
  • management-only credentials do not accidentally redefine the data-plane contract unless already intentionally accepted there;
  • unsupported methods against /v1/catalog are rejected.

Catalog parity

Tests should establish that the data-plane route and management route consume the same catalog authority.

A change to catalog generation should not require maintaining two independent serialization implementations.

Relevant properties include:

  • model entries;
  • reasoning metadata;
  • context metadata;
  • routed aliases;
  • ownership fields;
  • sanitization;
  • response bounds.

Documentation

Update the credential/surface documentation so the boundary is explicit.

The credential table should reflect conceptually:

Credential class Allowed surface
Data plane inference endpoints plus read-only /v1/models and /v1/catalog
Management plane /api/*
GUI session management API only, subject to GUI-session restrictions

Also document the multi-machine catalog-download workflow.

Relationship to #709

#709 implemented the generated catalog read on the management surface.

This issue does not replace or remove:

GET /api/catalog

The management route remains useful for the Dashboard/operator surface.

This issue adds the least-privilege remote-client projection of that same catalog.

Relationship to #95

#95 tracks the broader centrally hosted / multi-user OpenCodex deployment.

This issue addresses one concrete blocker from that deployment model:

remote clients need the Codex catalog
without receiving management privileges

It does not attempt to solve the rest of #95.

Out of scope

This issue does not require:

  • exposing models_cache.json;
  • moving the management API under /v1;
  • granting data-plane credentials general /api/* access;
  • remote provider configuration;
  • remote OAuth management;
  • distributing management credentials to client machines;
  • introducing a second catalog-generation implementation.

Acceptance criteria

  • GET /api/catalog exists on the management plane.
  • Maintainer-approved architecture uses a separate data-plane route rather than weakening /api/* authentication.
  • GET /v1/catalog exists.
  • HEAD /v1/catalog is supported if consistent with the existing read surface.
  • Existing data-plane credentials can read the route.
  • Catalog content comes from the same authoritative generator/payload contract as /api/catalog.
  • No credentials, provider configuration, or management-only state are exposed.
  • Non-read methods are rejected.
  • A data-plane credential still cannot access any /api/* route.
  • Positive and negative admission tests cover the credential boundary.
  • Response size/cache/version behavior remains bounded and documented.
  • Credential/surface documentation is updated.
  • Remote/multi-machine catalog-download workflow is documented.
  • Accepted implementation is merged into dev.

Related

Activity

  1. github-actions commented on Jul 31, 2026

    @github-actions
    Contributor

    Automated translation bookkeeping — detected language: English.

  2. added
    account-poolOAuth, credentials, Codex pool, quota, failover, plans
    catalogModel catalog, slugs, visibility, routed entries
    proxyHTTP proxy, routing, reverse-proxy / management auth
    streamingSSE, WebSocket, terminal stream frames
    on Aug 1, 2026
  3. Ingwannu commented on Aug 1, 2026

    @Ingwannu
    Owner

    Accepted. The least-privilege use case is valid, but we should not carve a data-token exception into the /api/* management prefix.

    The implementation direction is a separate read-only data-plane route (for example GET /v1/catalog) protected by the existing data-plane admission helper. It should reuse the same generated catalog payload and redaction rules as GET /api/catalog, remain GET/HEAD only, expose no configuration or credentials, retain response size/cache/version headers, and include negative tests proving the credential still cannot access any /api/* route or mutation.

    Please open the PR against dev with that route split and update the credential table in structure/05_gui-and-management-api.md plus the public reference docs.

  4. added
    maintainer-sponsoredMaintainer sponsors this change to an auth, workflow, release, or dependency surface
    and removed
    streamingSSE, WebSocket, terminal stream frames
    on Aug 3, 2026
  5. Wibias commented on Aug 8, 2026

    @Wibias
    Contributor

    Parent use case: #95

    This issue tracks the least-privilege catalog-distribution gap that remains for centrally hosted / multi-machine OpenCodex deployments.

  6. changed the title [-]Follow-up to #709: let a client credential read GET /api/catalog without management privileges[/-] [+][Feature]: add least-privilege GET /v1/catalog for remote Codex clients[/+] on Aug 9, 2026
  7. LeoWang331 commented on Aug 12, 2026

    @LeoWang331
    Contributor

    I'm working on a narrowly scoped implementation of the accepted data-plane /v1/catalog design. I'll open a dev-targeted draft PR after the first reviewable, green vertical slice so progress and scope are visible.

  8. lidge-jun commented on Aug 19, 2026

    @lidge-jun
    Owner

    리뷰 · 우선순위 66 / 80

    현재 dev에서 생성된 카탈로그를 받는 HTTP 경로는 GET /api/catalog뿐입니다. src/server/management/model-routes.ts에 있고 관리 평면입니다. /v1/catalog는 소스에서 검색되지 않습니다. 원격 Codex 클라이언트가 모델 메타데이터를 받으려면 관리 자격 증명이 필요하고, 그 자격 증명은 설정·OAuth·종료까지 엽니다.

    이슈가 원하는 것은 추론과 같은 데이터 플레인 자격 증명으로 읽기 전용 카탈로그를 받는 것입니다. 수락된 방향은 /api/catalog 입장을 느슨하게 하는 예외가 아니라 GET /v1/catalog(선택적 HEAD)입니다. 데이터 플레인 토큰은 /api/config, /api/providers, OAuth 로그인, /api/stop에서 계속 401이어야 합니다. #95의 중앙 호스팅에서 이 경계가 깨지면 테넌트 격리가 시작도 못 합니다.

    네이티브 신뢰성보다 위생과 원격/서비스 배포가 점수입니다. 페이로드는 /api/catalog와 같은 생성본·레드액션을 재사용해야 합니다. 두 번째 카탈로그를 만들면 모델 목록이 갈라집니다. 키, OAuth, 관리 토큰이 데이터 플레인 응답에 나오면 안 됩니다.

    LeoWang331이 좁은 슬라이스를 작업 중이라고 했으니, 그 PR은 입장 헬퍼 재사용, GET/HEAD만, 관리 경로 부정 테스트가 있어야 합니다. Windows 원격 클라이언트와 리버스 프록시 뒤에서 같은 데이터 플레인 헤더가 동작해야 합니다.

    해결방안은 기존 카탈로그 직렬화를 /v1/catalog에 붙이고, 데이터 플레인 입장만 쓰며, /api/*는 그대로 두는 것입니다. 패치는 추측하지 않으며, 현재 트리에 데이터 플레인 카탈로그 라우트는 없습니다.

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

  9. 4 remaining items

  10. added 2 commits that reference this issue on Sep 14, 2026
    b5a907f
    02d90a4
  11. added 4 commits that reference this issue on Sep 17, 2026
    a4936d8
    f1a3be5
    42a35b4
    648d20a
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, planscatalogModel catalog, slugs, visibility, routed entriesenhancementNew feature or requestmaintainer-sponsoredMaintainer sponsors this change to an auth, workflow, release, or dependency surfaceproxyHTTP proxy, routing, reverse-proxy / management auth

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions