Skip to content

WorkOS has no headless auth path, which is what keeps legacy GitHub App auth alive #535

Closed

Description

@alexeyzimarev

Follow-up to #534. That issue stops routing headless users onto legacy GitHub App auth; this one removes the reason the routing existed.

Problem

WorkOS sign-in cannot complete in a non-interactive environment, so headless kcap setup has no working auth path at all once #534 lands.

The blocker is not the inability to launch a browser — IBrowser is already injectable (OAuthLoginFlow.cs:527). It is the loopback redirect:

// OAuthLoginFlow.cs:525
var redirectUri = $"http://127.0.0.1:{GetAvailablePort()}/callback";

On a remote box (SSH, container) the user's browser runs on their laptop, so http://127.0.0.1:{port}/callback resolves to their laptop's localhost and never reaches the CLI's listener. GitHub App auth worked headless only because GitHub offers a device flow (RunDeviceFlowAsync → github.com/login/device/code) that needs no callback to the CLI's machine.

So: legacy auth is the only headless-capable provider today. That is the entire reason ChooseDiscoveryProvider falls back to it.

Options

A. OAuth 2.0 Device Authorization Grant via WorkOS. Cleanest — no callback, and it matches the UX users already know from the GitHub flow. Whether WorkOS supports the device grant is unverified. Nothing in kcap-server or kcap-web implements it today. This needs confirming first; it decides the shape and cost of the whole change.

B. Out-of-band paste-back. If WorkOS has no device grant: authorize in a browser on any machine, redirect to a kcap-web page that displays a short-lived one-time code, user pastes it into the CLI, CLI exchanges it for tokens. Needs a small web endpoint plus a short-TTL code store. No WorkOS feature dependency; a standard fallback for exactly this constraint.

Either way SpectreTenantProvisioner also needs a non-Spectre counterpart, since the current provisioner is nulled when headless (SetupCommand.cs:843) and prompts interactively for the slug.

Why it matters

Headless is not a rounding error: 1 of 9 real (non-CI, released-build) CLI setup devices was headless, and 1 of the 3 that reached the no-workspace fork. At the current ~3–5 signups/day that is roughly one affected person every 1–3 days. Small n — treat as an order of magnitude, not a rate.

Track it on the is_headless breakdown: https://eu.posthog.com/project/11377/insights/Cd3S4b0i

Definition of done

Headless kcap setup can authenticate with WorkOS and create a workspace without a local browser. GitHub App auth then serves only existing tenants via --server-url / --github and can go on a deprecation clock.

Activity

  1. linear-code commented on Aug 11, 2026

    @linear-code
  2. George-Payne commented on Aug 21, 2026

    @George-Payne
    Member

    Splitting this issue's definition of done across two changes, since #638 delivers the first half.

    In #638 — headless authentication. Option A: RFC 8628 device authorization grant against AuthKit's user_management endpoints, public client, no proxy involved. A CLI that cannot reach a 127.0.0.1 callback signs in, and LoginCommand.NewFacade no longer hardcodes provisioner: null, so an interactive SSH session — which has a TTY — now creates a workspace end to end. That is the population this issue measures.

    Tracked separately as AI-2163 — the non-Spectre provisioner. What remains terminal-bound is the create-a-workspace fork itself: the three-way prompt, the organization name and the slug are all Spectre prompts, so a session with redirected stdin authenticates and then stops with guidance instead of creating. Closing that needs --org/--slug, non-interactive slug-collision handling, and a decision on what --no-prompt means once those exist — scriptability work rather than auth work.

    No regression in the split: headless creation never worked on the GitHub App path either, since SetupCommand nulled the provisioner outright when headless. So the deprecation clock in "Why it matters" is not held up by AI-2163.

    Raised by @alexeyzimarev reviewing #638.

  3. realtonyyoung commented on Oct 18, 2026

    @realtonyyoung
    Collaborator

    Already done: #638 added the WorkOS device authorization grant and #667 the non-interactive --org/--slug provisioning, which together meet the definition of done. Closing in a backlog triage.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions