Add ChatGPT subscription provider via OAuth 2.0 PKCE#53166
Merged
Conversation
Adds a new language model provider that authenticates users with their ChatGPT Plus/Pro subscription using OpenAI's Codex CLI OAuth client, then routes requests to chatgpt.com/backend-api/codex/responses. - New openai_subscribed provider with OAuth PKCE sign-in flow - Stores credentials in the system keychain (access + refresh tokens) - Auto-refreshes tokens within 5 minutes of expiry - Exposes codex-mini-latest, o4-mini, and o3 models - Adds `store` field and `extra_headers` param to Responses API client
- Propagate refreshed credentials to in-memory State immediately after persisting, so subsequent requests don't redundantly refresh again - Clear sign_in_task when keychain write fails during OAuth, so the UI doesn't get stuck in a permanent "Signing in..." state
…vider - Replace the hardcoded CodexModel enum (3 models) with open_ai::Model, so all standard OpenAI models appear in the dropdown after signing in. - Add o4-mini as a proper variant in open_ai::Model. - Keep codex-mini-latest as a Custom model entry. - Add instructions field to responses::Request and extract system messages into it for the Codex backend (fixes 'Instructions are required' error). - Delegate to open_ai::Model for supports_images, max_output_tokens, count_tokens, and supports_parallel_tool_calls instead of hardcoding.
The Codex backend (chatgpt.com/backend-api/codex) only supports a subset of OpenAI models. Replace the open_ai::Model::iter() approach with a dedicated ChatGptModel enum listing only the models that work through the Codex backend, based on Roo Code's Codex model catalog: - gpt-5.4, gpt-5.4-mini - gpt-5.3-codex, gpt-5.3-codex-spark - gpt-5.2-codex, gpt-5.2 - gpt-5.1-codex-max, gpt-5.1-codex, gpt-5.1-codex-mini, gpt-5.1 - gpt-5-codex, gpt-5-codex-mini, gpt-5 Older models (gpt-3.5-turbo, gpt-4, o1, o3, etc.) and the deprecated codex-mini-latest are removed since they aren't available through this backend.
Multiple concurrent stream_completion calls seeing expired credentials would all independently call refresh_token(). With OAuth rotating refresh tokens, the first refresh invalidates the old token, causing all subsequent concurrent refreshes to fail. Add a Shared<Task> to State so the first caller to notice expiry spawns the refresh task and subsequent callers join the same future.
If the user starts the sign-in flow but never completes it in the browser, the TCP listener on port 1455 would block forever. Race the accept against a 2-minute timer so the port is released and the UI gets a meaningful error.
Replace hand-rolled format! string interpolation with url::form_urlencoded::Serializer in exchange_code and refresh_token. The previous code didn't percent-encode the code, verifier, or refresh_token values, which would break if they contained &, =, or +.
Early-return if a sign-in task is already in progress. Without this, a second call would drop the existing task (cancelling it while port 1455 may still be bound) and the new task could fail to bind.
Dropping sign_in_task prevents a completing OAuth flow from writing credentials back into state after the user has signed out.
The ConfigurationView was duplicating sign-out logic (missing the sign_in_task cancellation) and constructing a throwaway provider for sign-in. Extract both into free functions so the provider and the view share the same implementation.
The ConfigurationView shows 'Signed in as {email}' but the email
was never populated. OpenAI's token endpoint doesn't include email
at the top level — it's in the JWT id_token claims. Refactor
extract_account_id into extract_jwt_claims that parses the JWT once
and returns both account_id and email.
The hand-rolled percent_decode was incorrect for multi-byte UTF-8 (decoded each byte as an independent char). Use url::Url for building the auth URL and form_urlencoded::parse for decoding the callback query string. Remove both hand-rolled functions.
Previously a schema change or corruption would silently show the user as signed out. Now a log::warn helps diagnose the issue.
If the system clock is before the UNIX epoch, the silent unwrap_or(0) would cause broken credential expiry behavior. Now the error is visible in logs.
A single read() could miss query parameters if the browser's HTTP request is split across TCP segments. Read in a loop until the header terminator is found.
Add http_client::oauth_callback_page() that generates a nicely styled HTML page with Zed branding for OAuth callback responses. Use it in both the ChatGPT subscription provider and the MCP context server OAuth flow, replacing the unstyled inline HTML in both places. The template is parameterized on title and message so both callers get consistent styling that updates in one place.
smol::Timer::after is banned by a project-wide clippy lint. Pass the AsyncApp through to await_oauth_callback so it can use cx.background_executor().timer() instead.
7d1af89 to
64069d5
Compare
The into_open_ai_response call was hardcoding supports_parallel_tool_calls=true and supports_prompt_cache_key=false instead of asking the model. This meant reasoning models like GPT-5 Codex variants would incorrectly send parallel_tool_calls=true, which could cause API errors. Add the missing methods to ChatGptModel and delegate like the standard OpenAI provider does.
Three tests covering get_fresh_credentials: - test_concurrent_refresh_deduplicates: two concurrent callers with expired credentials only trigger one HTTP refresh call - test_fresh_credentials_skip_refresh: fresh credentials return immediately with no HTTP call - test_no_credentials_returns_no_api_key: missing credentials return the correct error variant
auth.openai.com was rejecting authorize requests with a generic AuthApiFailure / unknown_error because the redirect_uri and authorize query parameters did not match what is registered for the Codex CLI OAuth client that openai_subscribed reuses (CLIENT_ID app_EMoamEEZ73f0CkXaXp7hrann). OAuth servers compare redirect_uri by exact string match per RFC 6749 section 3.1.2, so host, port, and path all must match the per-client allow-list. http_client: - Add OAuthCallbackServerConfig (host, preferred_port, optional fallback_port, path) and start_oauth_callback_server_with_config. - Keep the existing start_oauth_callback_server as a thin wrapper using defaults (127.0.0.1, ephemeral port, /callback) so the MCP OAuth flow in context_server is unaffected. - Handle inbound GET /cancel in the worker to allow a new sign-in to evict a previous listener still bound to the port. - On bind failure with AddrInUse, send GET /cancel to the existing listener, retry up to 10 times with 200 ms backoff, then fall back to the optional secondary port and repeat. This mirrors the Codex CLI's bind_server / send_cancel_request handshake. openai_subscribed: - Bind the OAuth callback on localhost:1455 with fallback 1457 and path /auth/callback (the Codex CLI's Hydra-registered redirect URIs). - Add the authorize query parameters the Codex CLI sends and the OAuth client expects: extend scope with api.connectors.read and api.connectors.invoke, and send id_token_add_organizations=true. - Keep originator=zed (rather than codex_cli_rs); OpenAI appears to treat originator as telemetry rather than as an authorization decision, so honest attribution works here.
The Codex backend at chatgpt.com/backend-api/codex/responses rejects
`max_output_tokens` with `{"detail":"Unsupported parameter:
max_output_tokens"}`, unlike the public OpenAI Responses API at
api.openai.com/v1/responses which accepts it. The Codex CLI's
build_responses_request in codex-rs/core/src/client.rs never sets that
field on its ResponsesApiRequest for this reason.
Pass `None` to into_open_ai_response so `ResponseRequest::
max_output_tokens` stays `None` and, because the field is annotated
`#[serde(skip_serializing_if = "Option::is_none")]`, it is omitted from
the JSON body entirely. The model's max_output_tokens metadata is
preserved on the LanguageModel for token-counting and capability
checks; only the on-the-wire field is suppressed.
The hardcoded list contained nine slugs the Codex backend rejects with "The '<slug>' model is not supported when using Codex with a ChatGPT account": gpt-5, gpt-5-codex, gpt-5-codex-mini, gpt-5.1, gpt-5.1-codex, gpt-5.1-codex-max, gpt-5.1-codex-mini, gpt-5.2-codex, gpt-5.3-codex-spark. Replace with the five picker-visible models from OpenAI's bundled catalog (codex-rs/models-manager/models.json in openai/codex), which is what the Codex CLI ships as its authoritative fallback list when the dynamic /models endpoint isn't reachable: gpt-5.5, gpt-5.4, gpt-5.4-mini, gpt-5.3-codex, gpt-5.2. Per-model metadata is also corrected to match the bundled catalog: - Context window is 272K for every model. The Codex backend caps inputs at 272K even when the underlying model advertises a larger context window via the public Responses API (e.g. gpt-5.4 has max_context_window 1M). - All five models support parallel tool calls and image inputs. - Default reasoning effort is Medium for all five. - supports_none_reasoning_effort is now false everywhere: the bundled catalog's supported_reasoning_levels for every model is low/medium/high/xhigh, and sending `none` is rejected by the backend. Make gpt-5.5 the default model. Keep gpt-5.4-mini as the fast model (no gpt-5.5-mini exists yet; OpenAI's Codex docs recommend gpt-5.4-mini as the fast/cheap default alongside gpt-5.5). Add a TODO noting that even this corrected static list cannot represent per-account access gating (free accounts cannot use gpt-5.4 or gpt-5.3-codex even though paid accounts can); fully fixing that requires the dynamic /models fetch.
The previous version spawned a detached smol task whose only job was to translate `http_client::OAuthCallbackParams` into `OAuthCallback` and forward through a second oneshot channel. That introduced a hardcoded dependency on smol's executor and added a Task that the project's executor abstraction couldn't see. There's no work to spawn here: the translation is a pure mapping over the result of the inner receiver. Return a `BoxFuture` whose poll implementation awaits the inner receiver and maps the result inline, so there is no executor dependency at all. Make `start_callback_server` non-async (its body never awaited anything) and update the single caller in context_server_store. The caller's separate map_err for the canceled case is no longer needed because the future now produces the same anyhow error itself.
o4-mini was deliberately removed from the BYOK OpenAI provider in #49082 (0b8424a) on 2026-02-12 because OpenAI was retiring it (ChatGPT workspace support ended 2026-04-03). It was reintroduced as a `Model::O4Mini` variant in this branch's a603fea ("openai_subscribed: Show all OpenAI models in ChatGPT Subscription provider") because that refactor had the subscribed provider reuse `open_ai::Model` directly, and the Codex backend still accepted o4-mini for ChatGPT-subscription users at the time. That reuse is no longer in place: dd57d96 ("Trim ChatGPT subscription model list to match Codex backend") replaced it with a dedicated `ChatGptModel` enum scoped to the five picker-visible models from OpenAI's bundled catalog (gpt-5.5, gpt-5.4, gpt-5.4-mini, gpt-5.3-codex, gpt-5.2). Nothing on this branch needs `O4Mini` anymore, and its presence re-pollutes the BYOK provider dropdown with a model the previous deprecation PR removed. Remove the variant and its arms in `crates/open_ai/src/open_ai.rs` (`from_id`, `id`, `display_name`, `max_token_count`, `max_output_tokens`, `reasoning_effort`, `supports_parallel_tool_calls`) and the corresponding `supports_images` arm in `crates/language_models/src/provider/open_ai.rs`. The `"o4-mini"` strings in `crates/migrator/src/migrator.rs` test fixtures stay: those test the migration path for users whose old settings referenced o4-mini, which is still the correct behavior even after the model itself is gone.
The shared OAuth callback infrastructure (loopback HTTP listener, `OAuthCallbackParams`/`OAuthCallbackServerConfig`, `start_oauth_callback_server[_with_config]`, and the styled HTML response page) was living in `http_client`, which is not really "HTTP client" responsibility -- the callback flow is a server, not a client, and the hardcoded HTML response page is purely OAuth-flow presentation. The tight coupling also forced `http_client` to depend on `tiny_http`, which is unrelated to its actual surface. Move the module to a new `oauth_callback_server` crate at `crates/oauth_callback_server/`. The crate exposes the same public API (renamed nothing) so consumers only need an import path change: - `http_client::OAuthCallbackParams` -> `oauth_callback_server::OAuthCallbackParams` - `http_client::OAuthCallbackServerConfig` -> `oauth_callback_server::OAuthCallbackServerConfig` - `http_client::start_oauth_callback_server` -> `oauth_callback_server::start_oauth_callback_server` - `http_client::start_oauth_callback_server_with_config` -> `oauth_callback_server::start_oauth_callback_server_with_config` - `http_client::oauth_callback_page` -> `oauth_callback_server::oauth_callback_page` Update the two consumers (`context_server` and `language_models`) to depend on the new crate, drop `tiny_http` from `http_client`'s non-wasm dependencies (it has no remaining uses there), and remove the moved code from `http_client.rs`. The non-wasm-only server module stays gated with `#[cfg(not(target_family = "wasm"))]` inside the new crate; the `oauth_callback_page` HTML helper is unconditional because it just returns a `String`.
Two CI failures from 831c244 ("Extract OAuth callback server into its own crate"): - check_licenses: new crates need a LICENSE-{APACHE,GPL} symlink to the repo-root license file. Add LICENSE-APACHE symlink pointing to ../../LICENSE-APACHE, matching the crate's `license = "Apache-2.0"` metadata and the convention used by other Apache-licensed crates (e.g. http_client). - check_dependencies (cargo machete): `smol` is unused in context_server since 24703c9 ("Drop smol::spawn from MCP OAuth callback wrapper"). Remove the now-unused workspace dep from context_server/Cargo.toml.
rtfeldman
approved these changes
May 14, 2026
Collaborator
|
/cherry-pick preview |
Merged
5 tasks
Contributor
|
🍒💥 Cherry-pick did not succeed |
zed-zippy Bot
added a commit
that referenced
this pull request
May 14, 2026
…-pick to preview) (#56807) Cherry-pick of #53166 to preview ---- Adds a new language model provider that lets users authenticate with their ChatGPT Plus/Pro subscription and use OpenAI models (codex-mini-latest, o4-mini, o3) directly in the Zed agent — without needing a separate API key. ## How it works 1. **OAuth 2.0 + PKCE sign-in**: Uses OpenAI's official Codex CLI client ID to run an authorization code flow. A local HTTP server on `127.0.0.1:1455` captures the callback, exchanges the code for tokens, and stores them in the system keychain. 2. **Token refresh**: Access tokens are automatically refreshed when they're within 5 minutes of expiry, using the stored refresh token. 3. **Responses API**: Requests go to `https://chatgpt.com/backend-api/codex/responses` using the existing `open_ai::responses` client (Responses API format, not Chat Completions which was deprecated for this endpoint in Feb 2026). 4. **Required headers**: `originator: zed`, `OpenAI-Beta: responses=experimental`, `ChatGPT-Account-Id` (extracted from JWT), `store: false` in the body. ## Files changed - `crates/open_ai/src/responses.rs`: Add `store: Option<bool>` field to `Request`; add `extra_headers` param to `stream_response` for per-provider header injection - `crates/language_models/src/provider/openai_subscribed.rs`: New provider (sign-in UI, OAuth flow, token storage/refresh, model list) - `crates/language_models/src/provider/open_ai.rs`, `open_ai_compatible.rs`, `opencode.rs`: Pass `vec![]` for new `extra_headers` param - `crates/language_models/src/language_models.rs`: Register the new provider - `crates/language_models/Cargo.toml`: Add `rand` and `sha2` deps for PKCE ## Open questions / known gaps - [ ] **Terms of service**: Usage appears to be within OpenAI's ToS (interactive use via their official CLI client ID), but needs legal sign-off before shipping - [ ] **Redirect URI**: Currently `http://localhost:1455/auth/callback` — may need to match exactly what OpenAI's Codex CLI uses - [ ] **UI polish**: The sign-in card is functional but minimal; needs design review - [ ] **Error messages**: OAuth error responses from the callback URL aren't surfaced to the user yet - [ ] **`o3` availability**: o3 may require a higher subscription tier; consider gating it ## Testing Sign-in flow was designed to match the Copilot Chat provider pattern. Manual testing against the live OAuth endpoint is needed. Release Notes: - Added ChatGPT subscription provider, allowing users to use their ChatGPT Plus/Pro subscription with the Zed agent --------- Co-authored-by: Zed Zippy <234243425+zed-zippy[bot]@users.noreply.github.com> Co-authored-by: Richard Feldman <richard@zed.dev> Co-authored-by: Richard Feldman <oss@rtfeldman.com> Co-authored-by: Agus Zubiaga <agus@zed.dev> Co-authored-by: morgankrey <morgan@zed.dev> Co-authored-by: Zed Zippy <234243425+zed-zippy[bot]@users.noreply.github.com> Co-authored-by: Richard Feldman <richard@zed.dev> Co-authored-by: Richard Feldman <oss@rtfeldman.com> Co-authored-by: Agus Zubiaga <agus@zed.dev>
Collaborator
|
/cherry-pick stable |
5 tasks
zed-zippy Bot
added a commit
that referenced
this pull request
May 14, 2026
…-pick to stable) (#56811) Cherry-pick of #53166 to stable ---- Adds a new language model provider that lets users authenticate with their ChatGPT Plus/Pro subscription and use OpenAI models (codex-mini-latest, o4-mini, o3) directly in the Zed agent — without needing a separate API key. ## How it works 1. **OAuth 2.0 + PKCE sign-in**: Uses OpenAI's official Codex CLI client ID to run an authorization code flow. A local HTTP server on `127.0.0.1:1455` captures the callback, exchanges the code for tokens, and stores them in the system keychain. 2. **Token refresh**: Access tokens are automatically refreshed when they're within 5 minutes of expiry, using the stored refresh token. 3. **Responses API**: Requests go to `https://chatgpt.com/backend-api/codex/responses` using the existing `open_ai::responses` client (Responses API format, not Chat Completions which was deprecated for this endpoint in Feb 2026). 4. **Required headers**: `originator: zed`, `OpenAI-Beta: responses=experimental`, `ChatGPT-Account-Id` (extracted from JWT), `store: false` in the body. ## Files changed - `crates/open_ai/src/responses.rs`: Add `store: Option<bool>` field to `Request`; add `extra_headers` param to `stream_response` for per-provider header injection - `crates/language_models/src/provider/openai_subscribed.rs`: New provider (sign-in UI, OAuth flow, token storage/refresh, model list) - `crates/language_models/src/provider/open_ai.rs`, `open_ai_compatible.rs`, `opencode.rs`: Pass `vec![]` for new `extra_headers` param - `crates/language_models/src/language_models.rs`: Register the new provider - `crates/language_models/Cargo.toml`: Add `rand` and `sha2` deps for PKCE ## Open questions / known gaps - [ ] **Terms of service**: Usage appears to be within OpenAI's ToS (interactive use via their official CLI client ID), but needs legal sign-off before shipping - [ ] **Redirect URI**: Currently `http://localhost:1455/auth/callback` — may need to match exactly what OpenAI's Codex CLI uses - [ ] **UI polish**: The sign-in card is functional but minimal; needs design review - [ ] **Error messages**: OAuth error responses from the callback URL aren't surfaced to the user yet - [ ] **`o3` availability**: o3 may require a higher subscription tier; consider gating it ## Testing Sign-in flow was designed to match the Copilot Chat provider pattern. Manual testing against the live OAuth endpoint is needed. Release Notes: - Added ChatGPT subscription provider, allowing users to use their ChatGPT Plus/Pro subscription with the Zed agent --------- Co-authored-by: Zed Zippy <234243425+zed-zippy[bot]@users.noreply.github.com> Co-authored-by: Richard Feldman <richard@zed.dev> Co-authored-by: Richard Feldman <oss@rtfeldman.com> Co-authored-by: Agus Zubiaga <agus@zed.dev> Co-authored-by: morgankrey <morgan@zed.dev> Co-authored-by: Zed Zippy <234243425+zed-zippy[bot]@users.noreply.github.com> Co-authored-by: Richard Feldman <richard@zed.dev> Co-authored-by: Richard Feldman <oss@rtfeldman.com> Co-authored-by: Agus Zubiaga <agus@zed.dev>
2 tasks
21 tasks
Nkr1shna
pushed a commit
to neozed-industries/neo-zed
that referenced
this pull request
May 15, 2026
…53166) (cherry-pick to stable) (zed-industries#56811) Cherry-pick of zed-industries#53166 to stable ---- Adds a new language model provider that lets users authenticate with their ChatGPT Plus/Pro subscription and use OpenAI models (codex-mini-latest, o4-mini, o3) directly in the Zed agent — without needing a separate API key. ## How it works 1. **OAuth 2.0 + PKCE sign-in**: Uses OpenAI's official Codex CLI client ID to run an authorization code flow. A local HTTP server on `127.0.0.1:1455` captures the callback, exchanges the code for tokens, and stores them in the system keychain. 2. **Token refresh**: Access tokens are automatically refreshed when they're within 5 minutes of expiry, using the stored refresh token. 3. **Responses API**: Requests go to `https://chatgpt.com/backend-api/codex/responses` using the existing `open_ai::responses` client (Responses API format, not Chat Completions which was deprecated for this endpoint in Feb 2026). 4. **Required headers**: `originator: zed`, `OpenAI-Beta: responses=experimental`, `ChatGPT-Account-Id` (extracted from JWT), `store: false` in the body. ## Files changed - `crates/open_ai/src/responses.rs`: Add `store: Option<bool>` field to `Request`; add `extra_headers` param to `stream_response` for per-provider header injection - `crates/language_models/src/provider/openai_subscribed.rs`: New provider (sign-in UI, OAuth flow, token storage/refresh, model list) - `crates/language_models/src/provider/open_ai.rs`, `open_ai_compatible.rs`, `opencode.rs`: Pass `vec![]` for new `extra_headers` param - `crates/language_models/src/language_models.rs`: Register the new provider - `crates/language_models/Cargo.toml`: Add `rand` and `sha2` deps for PKCE ## Open questions / known gaps - [ ] **Terms of service**: Usage appears to be within OpenAI's ToS (interactive use via their official CLI client ID), but needs legal sign-off before shipping - [ ] **Redirect URI**: Currently `http://localhost:1455/auth/callback` — may need to match exactly what OpenAI's Codex CLI uses - [ ] **UI polish**: The sign-in card is functional but minimal; needs design review - [ ] **Error messages**: OAuth error responses from the callback URL aren't surfaced to the user yet - [ ] **`o3` availability**: o3 may require a higher subscription tier; consider gating it ## Testing Sign-in flow was designed to match the Copilot Chat provider pattern. Manual testing against the live OAuth endpoint is needed. Release Notes: - Added ChatGPT subscription provider, allowing users to use their ChatGPT Plus/Pro subscription with the Zed agent --------- Co-authored-by: Zed Zippy <234243425+zed-zippy[bot]@users.noreply.github.com> Co-authored-by: Richard Feldman <richard@zed.dev> Co-authored-by: Richard Feldman <oss@rtfeldman.com> Co-authored-by: Agus Zubiaga <agus@zed.dev> Co-authored-by: morgankrey <morgan@zed.dev> Co-authored-by: Zed Zippy <234243425+zed-zippy[bot]@users.noreply.github.com> Co-authored-by: Richard Feldman <richard@zed.dev> Co-authored-by: Richard Feldman <oss@rtfeldman.com> Co-authored-by: Agus Zubiaga <agus@zed.dev>
Nkr1shna
pushed a commit
to neozed-industries/neo-zed
that referenced
this pull request
May 15, 2026
…53166) (cherry-pick to stable) (zed-industries#56811) Cherry-pick of zed-industries#53166 to stable ---- Adds a new language model provider that lets users authenticate with their ChatGPT Plus/Pro subscription and use OpenAI models (codex-mini-latest, o4-mini, o3) directly in the Zed agent — without needing a separate API key. ## How it works 1. **OAuth 2.0 + PKCE sign-in**: Uses OpenAI's official Codex CLI client ID to run an authorization code flow. A local HTTP server on `127.0.0.1:1455` captures the callback, exchanges the code for tokens, and stores them in the system keychain. 2. **Token refresh**: Access tokens are automatically refreshed when they're within 5 minutes of expiry, using the stored refresh token. 3. **Responses API**: Requests go to `https://chatgpt.com/backend-api/codex/responses` using the existing `open_ai::responses` client (Responses API format, not Chat Completions which was deprecated for this endpoint in Feb 2026). 4. **Required headers**: `originator: zed`, `OpenAI-Beta: responses=experimental`, `ChatGPT-Account-Id` (extracted from JWT), `store: false` in the body. ## Files changed - `crates/open_ai/src/responses.rs`: Add `store: Option<bool>` field to `Request`; add `extra_headers` param to `stream_response` for per-provider header injection - `crates/language_models/src/provider/openai_subscribed.rs`: New provider (sign-in UI, OAuth flow, token storage/refresh, model list) - `crates/language_models/src/provider/open_ai.rs`, `open_ai_compatible.rs`, `opencode.rs`: Pass `vec![]` for new `extra_headers` param - `crates/language_models/src/language_models.rs`: Register the new provider - `crates/language_models/Cargo.toml`: Add `rand` and `sha2` deps for PKCE ## Open questions / known gaps - [ ] **Terms of service**: Usage appears to be within OpenAI's ToS (interactive use via their official CLI client ID), but needs legal sign-off before shipping - [ ] **Redirect URI**: Currently `http://localhost:1455/auth/callback` — may need to match exactly what OpenAI's Codex CLI uses - [ ] **UI polish**: The sign-in card is functional but minimal; needs design review - [ ] **Error messages**: OAuth error responses from the callback URL aren't surfaced to the user yet - [ ] **`o3` availability**: o3 may require a higher subscription tier; consider gating it ## Testing Sign-in flow was designed to match the Copilot Chat provider pattern. Manual testing against the live OAuth endpoint is needed. Release Notes: - Added ChatGPT subscription provider, allowing users to use their ChatGPT Plus/Pro subscription with the Zed agent --------- Co-authored-by: Zed Zippy <234243425+zed-zippy[bot]@users.noreply.github.com> Co-authored-by: Richard Feldman <richard@zed.dev> Co-authored-by: Richard Feldman <oss@rtfeldman.com> Co-authored-by: Agus Zubiaga <agus@zed.dev> Co-authored-by: morgankrey <morgan@zed.dev> Co-authored-by: Zed Zippy <234243425+zed-zippy[bot]@users.noreply.github.com> Co-authored-by: Richard Feldman <richard@zed.dev> Co-authored-by: Richard Feldman <oss@rtfeldman.com> Co-authored-by: Agus Zubiaga <agus@zed.dev>
This was referenced May 15, 2026
pull Bot
pushed a commit
to soitun/zed-ai
that referenced
this pull request
May 15, 2026
## Summary - Document the new ChatGPT Subscription provider from zed-industries#53166 - Add to the LLM Providers page alphabetically between Anthropic and DeepSeek - Cover sign-in flow, available models (GPT-5.5, GPT-5.3 Codex), and sign-out ## Test plan - [ ] Verify section renders correctly in docs preview - [ ] Confirm links and anchors work Release Notes: - N/A
zed-zippy Bot
added a commit
that referenced
this pull request
May 15, 2026
…ew) (#56905) Cherry-pick of #56828 to preview ---- ## Summary - Document the new ChatGPT Subscription provider from #53166 - Add to the LLM Providers page alphabetically between Anthropic and DeepSeek - Cover sign-in flow, available models (GPT-5.5, GPT-5.3 Codex), and sign-out ## Test plan - [ ] Verify section renders correctly in docs preview - [ ] Confirm links and anchors work Release Notes: - N/A Co-authored-by: morgankrey <morgan@zed.dev>
zed-zippy Bot
added a commit
that referenced
this pull request
May 15, 2026
…e) (#56906) Cherry-pick of #56828 to stable ---- ## Summary - Document the new ChatGPT Subscription provider from #53166 - Add to the LLM Providers page alphabetically between Anthropic and DeepSeek - Cover sign-in flow, available models (GPT-5.5, GPT-5.3 Codex), and sign-out ## Test plan - [ ] Verify section renders correctly in docs preview - [ ] Confirm links and anchors work Release Notes: - N/A Co-authored-by: morgankrey <morgan@zed.dev>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds a new language model provider that lets users authenticate with their ChatGPT Plus/Pro subscription and use OpenAI models (codex-mini-latest, o4-mini, o3) directly in the Zed agent — without needing a separate API key.
How it works
OAuth 2.0 + PKCE sign-in: Uses OpenAI's official Codex CLI client ID to run an authorization code flow. A local HTTP server on
127.0.0.1:1455captures the callback, exchanges the code for tokens, and stores them in the system keychain.Token refresh: Access tokens are automatically refreshed when they're within 5 minutes of expiry, using the stored refresh token.
Responses API: Requests go to
https://chatgpt.com/backend-api/codex/responsesusing the existingopen_ai::responsesclient (Responses API format, not Chat Completions which was deprecated for this endpoint in Feb 2026).Required headers:
originator: zed,OpenAI-Beta: responses=experimental,ChatGPT-Account-Id(extracted from JWT),store: falsein the body.Files changed
crates/open_ai/src/responses.rs: Addstore: Option<bool>field toRequest; addextra_headersparam tostream_responsefor per-provider header injectioncrates/language_models/src/provider/openai_subscribed.rs: New provider (sign-in UI, OAuth flow, token storage/refresh, model list)crates/language_models/src/provider/open_ai.rs,open_ai_compatible.rs,opencode.rs: Passvec![]for newextra_headersparamcrates/language_models/src/language_models.rs: Register the new providercrates/language_models/Cargo.toml: Addrandandsha2deps for PKCEOpen questions / known gaps
http://localhost:1455/auth/callback— may need to match exactly what OpenAI's Codex CLI useso3availability: o3 may require a higher subscription tier; consider gating itTesting
Sign-in flow was designed to match the Copilot Chat provider pattern. Manual testing against the live OAuth endpoint is needed.
Release Notes: