Skip to content

4b (experimental): finish 'Sign in with ChatGPT' OAuth connect flow #294

Description

@Weegy

4b (experimental): finish "Sign in with ChatGPT" OAuth connect flow

Part of the pluggable-LLM-provider feature (PR #292). The api-key path for OpenAI (incl. GPT-5.x) is shipped and live-verified. 4b — connecting a provider via a ChatGPT subscription (OAuth device flow) instead of an API key — is deliberately excluded from #292 because its end-to-end functionality hinges on an unresolved question (below). This issue tracks finishing it.

⚠️ Experimental / ToS grey area. Using a ChatGPT-subscription login to drive programmatic API calls is a grey area of OpenAI's terms — surface a clear notice in the UI and do not market it as an enterprise feature.

Prototype already written (for reference)

The pure, unit-tested core exists on branch backup/llm-provider-oauth-4b (commits 3e6691c + e966bd9), removed from #292:

  • packages/llm-provider/src/oauthDeviceFlow.ts — RFC 8628 device grant: requestDeviceCode / pollDeviceToken / refreshAccessToken / isAccessTokenExpired against the OpenAI Codex public client (app_EMoamEEZ73f0CkXaXp7hrann, token endpoint auth.openai.com/oauth/token, verify auth.openai.com/codex/device). All take an injected fetch + clock.
  • providerCredentials.ts — vault token storage (provider:<id>/oauth_*) + resolveProviderOAuthBearer (auto-refresh + persist).
  • providerFactory.tsresolveLlmProvider prefers the OAuth bearer when configured, else the api-key path (byte-identical).
  • 19 mocked-HTTP unit tests; Forge-reviewed (fixed a token-leak + a stale-token bug).

The gating question (must be answered first)

A "Sign in with ChatGPT" token's audience is OpenAI's Codex/Responses backend, not necessarily the standard Chat Completions API our openaiProvider adapter speaks.

Test to settle it (~2 min):

codex login --device-auth        # auth.openai.com/codex/device, enter code; token → ~/.codex/auth.json
curl https://api.openai.com/v1/chat/completions \
  -H "Authorization: Bearer <access_token>" -H "content-type: application/json" \
  -d '{"model":"gpt-5.4","messages":[{"role":"user","content":"ping"}],"max_completion_tokens":5}'
  • 200 → token speaks Chat Completions → 4b = connect-UI + correct baseURL. Small.
  • 401 / wrong audience → token speaks only the Codex/Responses backend → 4b needs a Responses-API adapter (separate, larger slice). Also confirm the exact device-authorization endpoint (the prototype's deviceAuthorizationEndpoint is best-effort).

Remaining work (once the audience is known)

  1. Re-land the prototype core from backup/llm-provider-oauth-4b.
  2. Backend connect route: POST /api/v1/admin/providers/oauth/{start,poll}start → device code + verification URL; poll → on success writeProviderOAuthTokens into the right SETTING_DEFS multi-scope set + reactivate. (Per-plugin credential scoping mirrors the api-key path.)
  3. Admin-UI "Sign in with ChatGPT" button + device-code modal + clear ToS notice (i18n en+de).
  4. If audience ≠ Chat Completions: a Responses-API adapter (or the correct baseURL).
  5. End-to-end test: connect → assign a plugin to the oauth path → a chat turn runs on the OAuth bearer.

Test levels (summary)

  • Unit (done on the backup branch): node --import tsx --test test/llmProviderOAuth*.test.ts — 19/19.
  • Audience (manual, above) — the decision gate.
  • E2E — after the connect UI/route + (maybe) Responses adapter land.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions