Skip to content

feat(web): onboarding offers Codex and xAI sign-in again (CL-8589) - #942

Merged
TheGreatAxios merged 2 commits into
mainfrom
cl-8589-oauth-onboarding
Sep 18, 2026
Merged

TheGreatAxios merged 2 commits into
mainfrom
cl-8589-oauth-onboarding

Conversation

@TheGreatAxios

Copy link
Copy Markdown
Contributor

Summary

Brings back "Continue with Codex" and "Continue with xAI" in onboarding. Both are subscription providers with no API key, so they sign in instead of taking one. The hub runs the whole loopback PKCE flow in its own process; the browser only ever sees an authorize URL, a login id, and the id of the credential the hub stored.

Design

  • The login lives in @corbits/oauth-core's new server-only ./hub subpath, mounted once inside the hub's Corbits block. It registers start/poll/cancel routes on the tenant router, behind the hub's own grant middleware. Providers are registered by the host as a name -> { oauthConfig, exchange, metadata? } map out of the already-pinned @corbits/codex-provider and @corbits/xai-provider, so the library depends on neither.
  • Tokens are persisted as a stock oauth_token credential — the same row shape, AAD-bound secret/refreshSecret encryption and creator grant the platform's own POST /credentials writes. Codex's ChatGPT account id rides in metadata; no raw id_token is ever stored.
  • The PKCE verifier and the callback listener never leave the hub process, and a login expires (five minutes) or cancels so an abandoned one releases the fixed loopback port its provider is pinned to (1455 for Codex, 1456 for xAI).
  • Web side: a useMutation starts the login and opens the authorize URL, a useQuery polls it and, on completion, mints the offering through shadowOffering — the exact catalog chain the API-key path walks. ShadowOfferingInput's secret became a union of "here is a key" and "here is the credential the hub already stored", so there is one mint chain rather than two.
  • Serving inference with those credentials needs the providers' Responses adapters in the sidecar. Nothing set SIDECAR_ADAPTER_MANIFEST before, and the process provisioner did not forward it, so both are added: the manifest lands in .env.example and the provisioner passes it to every sidecar it spawns.

Onboarding's provider step is the only caller of this form; Settings has no separate inference connect form to share it with.

Follow-up: nobody refreshes an expired oauth_token

Interchange has the seam (ServingRefresh in vendor/intx/db/src/model-source-resolution.ts, threaded through run-source-resolution and hub-sessions' credential push), but nothing in Workbench supplies it — the code that did was deleted with @corbits/connections. Neither stock credential resolution nor the adapter refreshes, so an expired Codex or xAI credential fails at inference until the person signs in again. The provider packages already ship refreshCodexTokens/refreshXaiTokens; wiring one of them into that seam is a separate change, not invented here. docs/local-dev.md says so plainly.

Changes

  • apps/hub/src/server.ts — mount mountOAuthLogin in the Corbits block (that block only)
  • apps/hub/package.json — pin @corbits/oauth-core
  • apps/hub/src/provisioners/process.ts — forward SIDECAR_ADAPTER_MANIFEST to spawned sidecars
  • apps/web/src/onboarding/provider-connect-step.tsx — the two sign-in options and the login flow
  • apps/web/src/settings/inference/{oauth-login.ts,api.ts,index.ts} — the login routes' client and the credential union
  • .env.example, docs/local-dev.md

Testing

bun run check green (typecheck, lint, format, 611 web tests). The library pin points at corbitsdev/corbits-oauth-core's hub-login-mount branch head (eb97fa7) until corbitsdev/corbits-oauth-core#6 merges; it should be re-pinned to the merge commit then.

Not verified live: the running dev stack serves the main checkout, not this worktree, and restarting it was out of scope. A real sign-in cannot complete here regardless.

@linear-code

linear-code Bot commented Sep 18, 2026

Copy link
Copy Markdown

CL-8589

Codex and xAI are subscription providers with no API key, so the
provider step now offers "Continue with Codex" and "Continue with xAI"
beside the key and local options. Clicking one starts a login on the hub,
opens the authorize URL in a new tab, polls the login, and then mints the
offering over the credential the hub stored -- the same catalog chain the
API-key path walks, differing only in where the secret came from.

The hub mounts @corbits/oauth-core's new hub subpath inside the Corbits
block and registers the two providers out of the already-pinned provider
packages, so the loopback PKCE flow, the callback listener and the token
exchange all stay in the hub process and the browser never holds a token.

The sidecar needs the matching Responses adapters to serve inference with
those credentials: .env.example now carries the manifest, the process
provisioner forwards it to every sidecar it spawns, and docs/local-dev.md
says what the flow needs and that nothing refreshes an expired token yet.
@TheGreatAxios
TheGreatAxios force-pushed the cl-8589-oauth-onboarding branch from 6934ca6 to 63332ef Compare September 18, 2026 19:34
@TheGreatAxios
TheGreatAxios merged commit d83c934 into main Sep 18, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant