aaif-goose / aaif-goose/goose

gdk UniFFI has no OAuth surface — only API-key provider constructors

Open
#11,225 2 comments 0 reactions 1 assignee Claimed by @jamadeo View on GitHub
Dominant language
Rust
Stars
54.2k
Forks
6.2k
Avg merge
3d 4h
Merged PRs (30d)
240

Description

**What problem would this solve?**

Embedders that consume `io.github.aaif-goose:gdk` / `goose-sdk` (Kotlin/Python UniFFI) can construct API-key providers and stream, but they cannot run any of the OAuth flows goose already has in the CLI.

We probed published `gdk` `0.1.0-alpha.4` from a Kotlin Multiplatform app (Secret). These constructors work in-process with no network:

| Constructor | Default model | Features we saw |
|---|---|---|
| `openai_provider` | `gpt-4o` | streaming, tools, JSON schema, images, reasoning |
| `anthropic_provider` | `claude-sonnet-4-5` | same family |
| `groq_provider` | `moonshotai/kimi-k2-instruct-0905` | streaming, tools, JSON schema |
| `databricks_provider` / `databricks_v2_provider` | host + PAT | token only — `DatabricksAuth::token` |
| `declarative_provider_from_json` | custom OpenAI-compat | what we use for Hedwig / Ollama |

There is no UniFFI export for:

- RFC 8628 device-code (`crates/goose/src/providers/oauth_device_flow.rs`)
- GitHub Copilot (`githubcopilot.rs` — device code → GitHub token → `copilot_internal/v2/token`)
- Gemini installed-app OAuth (`gemini_oauth.rs`)
- ChatGPT Codex PKCE (`chatgpt_codex.rs`)
- Databricks OAuth (gdk only takes a PAT)
- `configure_oauth` / token refresh / a callback the host can use to open a browser or show a user code

So a mobile/desktop host that wants “Sign in with GitHub / Google / ChatGPT” has to reimplement those flows, then feed gdk a bearer token. That works, but it means every embedder forks goose’s OAuth instead of sharing it.

This is separate from #11006 (Buzz / Codex / ACP). That issue is about extracting Codex OAuth into `goose-providers` and an ACP surface. This one is: **the already-published UniFFI bindings never grew an auth API**, even for flows that already exist in `crates/goose`.

**What would a good outcome look like?**

A host can:

1. Ask gdk which providers support OAuth and which grant (device-code vs PKCE vs PAT).
2. Start a flow and get back either a verification URL + user code (device) or a localhost/redirect URL (PKCE).
3. Poll or wait until gdk returns an access token (and optional refresh).
4. Construct the matching `Provider` with that token — same object as today’s `openai_provider(api_key)`.
5. Refresh / revoke without the host knowing provider-specific token URLs.

The host still owns UI (open browser, show the code). gdk owns the protocol, client ids goose already ships, and token exchange. No requirement that gdk pop a browser itself.

**Possible approaches**

1. **Export the existing device-flow helper** (`DeviceFlowConfig` + start/poll/refresh) plus thin wrappers for Copilot / Kimi. Smallest, covers the RFC 8628 providers. PKCE (Codex, Gemini) stays host-side or follows later.
2. **One `start_oauth(provider_id)` / `poll_oauth(handle)` UniFFI pair** that dispatches to the provider’s `configure_oauth`. Matches how the CLI already works. Needs a place to persist secrets — today those paths live in goose core (`Config`, `private_file`), not `goose-sdk`.
3. **Do nothing in gdk; document “host does OAuth, pass a token.”** Honest, and what we shipped. Cost: every embedder reimplements Copilot’s two-step exchange and Codex PKCE, and client ids drift.

I’d take (1) then (2). (3) is the status quo and is why I’m filing this.

Constraints:

- Device-code is the only grant that works on a phone without a custom URL scheme.
- PKCE with `localhost:1455` (Codex) does not work headless or on mobile without a documented token-reuse path — #11006 already calls this out.
- Do not put goose’s OAuth client secrets into a new public API without saying they are public installed-app credentials (Copilot’s `Iv1.b507a08c87ecfe98` is already in-tree).

**Additional context**

- Bindings today: `crates/goose-sdk/src/bindings.rs` (`openai_provider`, `anthropic_provider`, `groq_provider`, `databricks_provider`, `declarative_provider_from_json`). No `oauth` symbol.
- CLI flows: `oauth_device_flow.rs`, `githubcopilot.rs`, `gemini_oauth.rs`, `kimicode.rs`, `chatgpt_codex.rs`.
- Related: #11006, #11007 (extract Codex/Claude into `goose-providers`).

- [x] I have verified this does not duplicate an existing feature request

Do not begin implementation until the issue reaches **Ready** on the [Goose Issues board](https://github.com/orgs/aaif-goose/projects/1).

Contributor guide

Open the contributing guide

Research direction

Start by reading the existing UniFFI bindings in `crates/goose-sdk/src/bindings.rs` and the OAuth implementations in `crates/goose/src/providers/`. Look at `oauth_device_flow.rs` and `githubcopilot.rs` to understand the flows. The goal is to design and expose a new OAuth surface in the UniFFI layer, allowing hosts to start and poll OAuth flows without reimplementing them. A successful outcome would be new exported functions in the bindings that match the CLI's OAuth capabilities, documented for embedders.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
api, backend
Issue type
Feature
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.