WikifitaGitHub live67e8de5
pesquisa · openai-research/flow-a-standalone

Flow A Standalone — Verified Building Blocks

Every fact needed to run the attested chat-submode flow outside the desktop app — refresh (oai_is), Node DeviceCheck token, real headers/bodies, conduits, attestation challenge

Baixar raw

Flow A Standalone — Verified Building Blocks

HISTORICAL / SUPERSEDED — 2026-08-27. This page describes the A0 ("standalone PKCE") attempt and its building blocks as of 2026-08-26. The validated sequence today is A1 (session-keeper): flow-a-manual-step-by-step (request by request, with exact headers/bodies) — see flow-definitions for the flow map. Keep the earlier claims below only as the historical record of A0; do not present them as the current protocol.

Part of openai-research. Historical record: every item below was verified on 2026-08-26 with zero requests against the chat backend beyond what the app itself did (auth test + addon load are local/read-only; the refresh is the standard OAuth rotation).

1. Auth (full PKCE route for the standalone probe)

  • Chosen route for the flow-A standalone probe: full PKCE (real browser login) — auth.openai.com/oauth/authorize (+ PKCE S256, callback localhost:1455, scope openid profile email offline_access api.connectors.read api.connectors.invoke (the full login scope), extras codex_cli_simplified_flow + id_token_add_organizations), exchange form-urlencoded, tokens persisted in a probe-own file (never ~/.codex/auth.json), refresh handled by the probe.
  • "Preemptive refresh" = always check the TTL before every request (parse exp of the access token; refresh when exp - now <= 5min or last_refresh > 8d); never send an expired token. It is NOT a scheduled/cron refresh. (Semantics = codex-rs should_refresh_proactively.)
  • OAuth refresh (proven standalone): POST https://auth.openai.com/oauth/token JSON {client_id: app_EMoamEEZ73f0CkXaXp7hrann, grant_type: "refresh_token", refresh_token}200 with keys access_token, token_type, expires_in (864000), scope, id_token, earliest_refresh_at, refresh_token, oai_isoai_is is a new field of the OAuth refresh response (integrity token; NOT used by codex-rs; not observed as a header in the desktop f/* requests).

2. Attestation (Node, no app)

require('/Applications/ChatGPT.app/Contents/Resources/native/devicecheck.node') in a plain Node process → generateToken(){supported: true, tokenBase64: "AgAA…" (2980), latencyMs}. No entitlement/signature dependencies (see attestation-flow).

3. Request surfaces (real captured values)

UA (version-pinned, safe to hardcode for THIS build): Codex Desktop/26.820.60940 (Mac OS; arm64)originator: Codex Desktop.

oai-did — DYNAMIC (application logic, replicable): the renderer keeps it in localStorage under key codex.chatgpt-conversations.device-id (webview; verified persisted in ~/Library/Application Support/Codex/Default/Local Storage/leveldb/…ldb); _Nr() reads it, generates with a UUID (Ug() — crypto.randomUUID family) and persists on first run. The standalone probe must do the same: randomUUID() v4 + persist (own file) — never reuse the app's captured UUID.

Attestation challenge: GET /backend-api/ios/attestation_challenge with Authorization: Bearer, ChatGPT-Account-Id: aa06cafc-…, OAI-Language: en-US, oai-did, originator: Codex Desktop, and x-sentinel-dc: {"token": "<DeviceCheck tokenBase64>"}{attestation_challenge: gAAAAAB…}.

Conversation POST /backend-api/f/conversation headers (real, captured): OAI-Language: en-US, oai-did, x-conduit-token (JWT ES256 from the prepare), Content-Type: application/json, Authorization: Bearer, ChatGPT-Account-Id, originator: Codex Desktop, User-Agent: Codex Desktop/26.820.60940 (Mac OS; arm64).

Body (first turn, real): {action:"next", local_function_signatures:[handoff…], messages:[<full user record: author{metadata,name:null,role:"user"}, channel:null, content:{content_type:"text", parts:[text]}, create_time, end_turn:null, id:<uuid>, metadata:{}, recipient:"all", status:"finished_successfully", update_time:null, weight:1>], model:"gpt-5-6-thinking", supported_encodings:["v1"], thinking_effort:"extended", timezone:"America/Sao_Paulo", timezone_offset_min:180, client_prepare_state:"success", app_attest_challenge:"gAAAAAB……"}.

Prepare (typing/warm): POST /f/conversation/prepare {action:"next", client_prepare_state:"sent", [partial_query…], local_function_signatures, model, thinking_effort, timezone, timezone_offset_min} with header x-conduit-token: no-token → returns the conduit_token (used as x-conduit-token header in the conversation JWT: conduit_uuid, conduit_location: 10.x.x.x:8304, cluster: unified-83).

Multi-turn: next turn body adds conversation_id + parent_message_id (+ the injected handoff result message with role:"tool", channel:"commentary", content:{content_type:"code", text:'{"call_id":…,"result":{"accepted":true,…}}'}) and a fresh app_attest_challenge.

SSE response: delta v1 (see response-sse-real) — the model's web search runs server-side (the only "http" the probe ever makes is to chatgpt.com backend; the web.run results come back inside the stream).

NOTE (2026-08-27): superseded in part — the VALIDATED end-to-end sequence is flow-a-manual-step-by-step (A1, session-keeper via the running app-server). The lesson additions since this page was written: the oai-did is the persisted installation identity (never regenerated; live from the renderer), the /f/conversation may carry x-conduit-token or not — the app alternates; when it is carried, the request must land on the conduit's cluster (a mismatch = 403 "Unusual activity"); the live authToken comes from getAuthStatus {includeToken:true} (the static auth.json can lag).

4. What this means (probe constraints)

  • Probe is non-golden: it runs NOW, with the bezetacil running (it reads the app version + quota surface from the harness; a guard check verifies the harness is online before starting). No --app-dir fallback, no atemporality (hardcoded version comes from the harness in this phase).
  • The addon used by the probe: extracted to ~/.bezetacil-chatgpt/scratchpad/devicecheck.node (gitignored; not version-dependent, no signature requirement — see attestation-flow).
  • The whole flow A is reproducible from Node + the addon + its own tokens, app closed (no Electron, no onboarding state, no browser after the login). The only macOS requirement is the OS (DeviceCheck).
  • Quota note: chat submode generation consumes chat quota (not codex); the observed snapshot (post-realtime) lives in work-runtime-trace/the quota trigger.
  • Correction: X-OAI-IS is NOT present in any captured desktop request header (f/, wham/ — 0 occurrences across sessions); it was a claim from the web/vendor analysis. The refresh response field is oai_is (integrity data for the OAuth token path). See chatgpt-desktop-architecture note.

Cross-references