diff options
Diffstat (limited to 'docs/oauth-provider-auth.md')
| -rw-r--r-- | docs/oauth-provider-auth.md | 72 |
1 files changed, 72 insertions, 0 deletions
diff --git a/docs/oauth-provider-auth.md b/docs/oauth-provider-auth.md index 9ae63a7..a29f13b 100644 --- a/docs/oauth-provider-auth.md +++ b/docs/oauth-provider-auth.md @@ -493,3 +493,75 @@ None of these are required for Copilot or Codex auth correctness. - The correct Codex subscription-backed model request endpoint and wire API. - Whether to add OS keychain storage in the first pass or after file-backed auth works end to end. + +--- + +## Implementation status (as built) + +The first pass landed as a clean break (no compatibility shim): every networked +provider must name an `[auth.<name>]` session via `auth = "<name>"`; +provider-level `api_key`/`api_key_env_var` are gone. Resolved decisions for the +open questions above: TOML uses `key_env_var`; `auth` is required for networked +providers; Codex device auth is modelled as a `dialect = "codex"` variant of +the generic `oauth_device` type; keychain storage is deferred (file-backed +`$PANTO_HOME/auth/<name>.json`, owner-only `0600`). + +### What core owns (libpanto) + +- `auth.zig` — auth config types (`AuthConfig`), the persisted `TokenSet`, token + storage (load/save/delete), the device flow (both dialects), refresh, the + Copilot exchange, JWT `exp` parsing, Codex account-id extraction, and the + pure credential/refresh-predicate helpers. No Lua dependency. +- `http_helper.zig` — a non-streaming request/response helper over the + process-global `std.http.Client`, plus dotted-JSON-path readers. +- Providers gained `extra_headers`, merged onto the built-in request headers. + +### What the CLI owns (`src/`) + +- `config_file.zig` parses `[auth.<name>]` and the `auth = "<name>"` reference, + resolving `api_key` sessions eagerly (literal/env). Providers always survive + resolution; an unresolved session fails the request with a clear error. +- `auth_manager.zig` resolves the active provider's auth before each turn + (load → login → refresh → exchange → build credential), patching the live + `ProviderConfig` (bearer, dynamic `base_url`, merged headers). +- The TUI runs an inline device login when no token is stored, and forces one + refresh/exchange retry on a `ProviderAuthFailed` (401/403). +- `panto auth status | login <name> | logout <name>` subcommands provide a + line-based login path outside the TUI. + +### Device-flow specifics (verified against reference clients) + +- **GitHub Copilot** (`dialect = "token"`): request `/login/device/code`, poll + `/login/oauth/access_token` until the OAuth token (`ghu_…`) arrives, then a + per-~30-min exchange (GET `/copilot_internal/v2/token`) yields the chat token, + its expiry, and `endpoints.api` (the runtime `base_url`). Copilot speaks the + OpenAI Chat Completions wire format, so it is a plain `openai_chat` provider — + this path is structurally complete. +- **OpenAI Codex** (`dialect = "codex"`): POST + `…/deviceauth/usercode` → poll `…/deviceauth/token` (403/404 = pending). The + poll **returns a server-generated PKCE `code_verifier` alongside the + authorization code**, so the client does *not* generate PKCE for device flow; + it relays the verifier when exchanging the code at `/oauth/token` for + `{access,refresh,id}_token`. Refresh uses `grant_type=refresh_token`. The + account id comes from the `id_token` JWT claim `https://api.openai.com/auth` + → `chatgpt_account_id`, sent as `chatgpt-account-id`. + +### Codex model endpoint — resolved open question + +Research confirmed the Codex subscription endpoint is **not** Chat Completions: +it is the OpenAI **Responses API** at +`https://chatgpt.com/backend-api/codex/responses` (request body uses `input` +items, `reasoning`, `include: ["reasoning.encrypted_content"]`, `store: false`; +headers `Authorization: Bearer`, `chatgpt-account-id`, +`OpenAI-Beta: responses=experimental`, `originator: codex_cli_rs`). That is a +new wire dialect, implemented as the `openai_responses` provider style (see +below), distinct from `openai_chat`. + +### Verification status + +Unit tests cover config parsing, token storage round-trips, JWT/account-id +extraction, credential building, refresh/exchange predicates, form encoding, +and header merging. The HTTP-dependent flows (device login, refresh, exchange, +Responses streaming) follow verified reference implementations but require live +credentials (a GitHub Copilot subscription / a ChatGPT plan) to confirm +end-to-end against the real endpoints. |
