github / github/copilot-sdk

Add programmatic device-code login to CopilotClient

Offen
#1,109 0 Kommentare 1 Reaktion 0 zugewiesene Personen Auf GitHub ansehen
Vorherrschende Sprache
Java
Sterne
10.5k
Forks
1.5k
Ø Merge
1 T. 11 Std.
Gemergte PRs (30 T.)
127

Beschreibung

### Problem

`CopilotClient` exposes `GetAuthStatusAsync` so callers can detect an unauthenticated state, but there is no SDK method to *transition* the session into an authenticated one. The only auth inputs today are:

- `CopilotClientOptions.GitHubToken`
- `GITHUB_TOKEN` / `GH_TOKEN` env vars
- Pre-existing cached credentials under `~/.copilot/` from a prior interactive `copilot /login` run

This works on machines where credentials have already been seeded — typical on Windows where the Copilot Chat extension or `gh copilot` may have populated the cache — but on a fresh macOS or Linux install there is no in-SDK path to bootstrap auth. The only options are:

1. Require the caller to supply a Personal Access Token. PATs are blocked by policy in many environments and can't be issued at all for some account types.
2. Launch the bundled CLI binary (`runtimes//native/copilot`) out-of-band and have the user run `/login` interactively, then re-enter the SDK once the credential file lands on disk.

Option 2 forces every SDK consumer to:

- Locate the bundled CLI binary across RIDs.
- Manage an external process lifecycle (cancellation, orphan cleanup, exit-code handling).
- Surrender stdio to the embedded CLI, which precludes custom UX, headless flows, and structured logging.
- Bypass the SDK's normal RPC contract entirely for this one capability.

### Proposal

Add a programmatic device-code OAuth flow to `CopilotClient` that yields the verification URL and user code via a callback (or an `IAsyncEnumerable` of state events) so consumers can render the prompt in their own UI:

```csharp
public Task LoginAsync(
LoginOptions options,
CancellationToken cancellationToken = default);

public sealed class LoginOptions
{
/// Invoked once with the device code + verification URL the user must visit.
public Action? OnDeviceCode { get; init; }

/// Optional override for the OAuth client / scopes if the SDK supports more than one tier.
public string? ClientId { get; init; }
}

public sealed record DeviceCodePrompt(
string UserCode,
Uri VerificationUri,
TimeSpan ExpiresIn,
TimeSpan PollInterval);

public sealed record AuthResult(
bool Success,
string? AccountLogin,
string? FailureReason);
```

After `LoginAsync` returns successfully, `GetAuthStatusAsync` should reflect the new state and subsequent RPC calls (`models.list`, `session.send`, etc.) should succeed without restarting the client.

A complementary `LogoutAsync()` that clears the cached credentials would round out the surface but is lower priority.

### Why this belongs in the SDK

- **Parity with `gh auth`, Octokit's device flow, and the VS Code Copilot extension** — all of which provide a programmatic device-code path. The SDK is the only Copilot client that requires shelling out to authenticate.
- **No-PAT bootstrap** — enables the SDK to be used in environments where PATs are unavailable or restricted, without forcing a separate CLI install.
- **Single source of truth for credential storage** — the SDK already reads `~/.copilot/`; centralizing the write path here prevents callers from drifting if the storage format changes.
- **Cancellable, awaitable, structured** — replaces an opaque interactive subprocess with a normal async API that cooperates with `CancellationToken`, structured logging, and host-defined UX.
- **Headless / CI scenarios** — a callback-based device flow can be driven by automation (forwarding the code to chat, email, a webhook, etc.); an interactive subprocess cannot.

### Alternatives considered

1. **Document the shell-out** — pushes the same complexity into every SDK consumer.
2. **Expose a `LoginUri` / `LoginPoll` pair** instead of a single `LoginAsync` — more flexible but pushes polling logic onto callers.
3. **Reuse `gh auth` tokens** — only works where `gh` is installed and authorized for the right account; not portable and still needs an external tool.

A first-class `LoginAsync` on `CopilotClient` is the smallest API addition that closes the gap.

Beitragsleitfaden

Beitragsleitfaden öffnen

Bewertung

Dieses Issue wurde noch nicht bewertet.

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.