Skip to content

feat(login): headless OAuth via --no-browser / --callback-url - #198

Draft
tonychang04 wants to merge 1 commit into
mainfrom
feat/login-no-browser
Draft

feat(login): headless OAuth via --no-browser / --callback-url#198
tonychang04 wants to merge 1 commit into
mainfrom
feat/login-no-browser

Conversation

@tonychang04

@tonychang04 tonychang04 commented Jul 16, 2026

Copy link
Copy Markdown
Member

Why

When the CLI runs inside a sandbox (ChatGPT app plugin, SSH, containers), insforge login opens the browser on the host, but the OAuth redirect goes to a loopback listener inside the sandbox that the host browser can never reach — login hangs until timeout. Seen live driving the InsForge plugin from the ChatGPT app (npx @insforge/cli@latest orgs list --json → auth URL → browser dead-ends on http://127.0.0.1:38961/callback?...).

What

Two-step headless flow, following the gcloud --no-launch-browser pattern (no backend changes needed):

  1. insforge login --no-browser — prints the authorize URL, persists PKCE verifier/state/redirect_uri to ~/.insforge/pending-login.json (0600, 10-min TTL matching the server's code expiry), exits.
  2. User signs in; the browser lands on the dead 127.0.0.1 redirect (expected — instructions say so) with code+state in the address bar.
  3. insforge login --callback-url "<pasted url>" — parses code/state (tolerates quotes/whitespace, bare query strings; surfaces error= params), verifies state, exchanges the code with the persisted verifier, stores credentials, deletes the pending file.

Default browser flow unchanged; its non-TTY output now hints at the fallback. Telemetry method distinguishes oauth_no_browser / oauth_callback_url.

Verification

  • 11 new unit tests (parse, pending persistence, state mismatch, expiry, full exchange with mocked fetch); full suite 595 passing, eslint clean, build clean.
  • Live smoke test against prod: --no-browser writes pending state + prints URL (human & --json modes); wrong state → local error; correct state + fake code reaches the real token endpoint and gets invalid_grant — full exchange wiring accepted server-side.

Notes

  • Companion docs PR needed in the skills repo (skills/insforge-cli/references/login.md) — will link.
  • Longer-term we may want a Supabase-style poll-based login (no paste at all); this PR is the zero-backend-change unblock.
  • No version bump included — will bump on release per DEVELOPMENT.md.

🤖 Generated with Claude Code

https://claude.ai/code/session_01GcszudKMZBSm5RMP14h7fu


Summary by cubic

Adds a headless OAuth login flow to the CLI with --no-browser and --callback-url so login works in sandboxes/SSH where loopback callbacks fail. Default browser login is unchanged; non-TTY mode now suggests the fallback.

  • New Features
    • insforge login --no-browser: prints the auth URL and saves pending PKCE/state/redirect_uri to ~/.insforge/pending-login.json (0600, 10‑min TTL).
    • insforge login --callback-url "<url>": parses code/state (tolerates quotes/whitespace or bare query strings), surfaces provider errors, verifies state/expiry, exchanges the code, stores credentials, and clears the pending file.
    • Telemetry records oauth_no_browser and oauth_callback_url methods.
    • Non‑TTY browser flow now hints at using --no-browser if the callback can’t reach the process.

Written for commit 03f9a07. Summary will update on new commits.

Review in cubic

Note

Add headless OAuth login via --no-browser and --callback-url flags

  • --no-browser generates PKCE/state, persists a pending login file, and prints an authorize URL with instructions instead of starting a local callback server.
  • --callback-url <url> completes a pending headless login by parsing the pasted callback URL, verifying state, exchanging the auth code, and storing credentials; enforces a 10-minute TTL on the pending login.
  • Pending login state is stored in a new PENDING_LOGIN_FILE in the global config directory with 0600 permissions via new helpers in config.ts.
  • Non-interactive performOAuthLogin now prints extra stderr guidance suggesting the --no-browser flow when the browser cannot reach the machine.
  • Behavioral Change: telemetry method values now include oauth_no_browser and oauth_callback_url in addition to existing values.

Macroscope summarized 03f9a07.

In sandboxed environments (ChatGPT app, SSH, containers) the browser can
never reach the CLI's loopback callback server, so browser login hangs
forever. Split the flow into two invocations:

- login --no-browser: prints the authorize URL and persists PKCE
  verifier/state to ~/.insforge/pending-login.json (0600, 10-min TTL
  matching the server's authorization-code expiry), then exits.
- login --callback-url <url>: accepts the full redirect URL copied from
  the browser address bar (the 127.0.0.1 page shows a connection error
  but the code/state survive in the URL), verifies state, exchanges the
  code with the persisted verifier, and stores credentials.

The default browser flow is unchanged; its non-TTY output now hints at
the fallback.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GcszudKMZBSm5RMP14h7fu
@coderabbitai

coderabbitai Bot commented Jul 16, 2026

Copy link
Copy Markdown

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 3756c470-c21d-4810-ae74-03936e235061

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/login-no-browser

Comment @coderabbitai help to get the list of available commands.

timothybrush pushed a commit to timothybrush/insforge-skills that referenced this pull request Jul 16, 2026
…-url)

Companion to InsForge/CLI#198. In sandboxes like the ChatGPT app the
browser cannot reach the CLI's loopback callback, so browser login hangs;
the new two-step flow prints the auth URL, the user pastes back the
redirect URL, and the CLI redeems it.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GcszudKMZBSm5RMP14h7fu
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