feat(providers): add xAI Grok subscription OAuth (device-code) + per-provider session auth
First subscription-OAuth provider beyond Kimi Code (26th registry variant). Log in with a Grok/SuperGrok/X subscription via RFC-8628 device-code OAuth (auth.x.ai), then use it against api.x.ai/v1 — reusing the existing xai wire (ChatCompletions + OpenAI listing + Passthrough + restrict + models_dev_id xai). Sourced from Pi (earendil-works/pi auth/oauth/xai.ts): client b1a00492..., scope 'openid profile email offline_access grok-cli:access api:access', standard Bearer (no x-xai-token-auth). Foundation (generalizes Kigi's Kimi-singleton OAuth to per-provider, root cause, not a patch): - Registry: OAuthConfig on PlatformSpec (client_id/host/device+token paths/scope/scope_key); XAI_OAUTH_CONFIG + XAI_GROK_SPEC (uses_oauth, method id 'xai-grok', an interactive login after kimi-code). - Generic device-code wire (auth/oauth_device.rs) + GenericDeviceRefresher, sharing the RFC-8628 core with Kimi; Kimi's bespoke flow is byte-identical (X-Msh headers, KIMI_CODE_OAUTH_SCOPE, keyring gating unchanged). - Per-provider AuthManager via a process-global pool (auth/oauth_registry.rs): build-on-demand with start_proactive_refresh, keyed by scope. The session resolves the AuthManager for the ACTIVE model's platform for bearer/refresh/ 401-recovery/api_key — an oauth-platform model always uses its OWN token, never the primary. - Live /models under OAuth; base routes oauth().is_some() -> platform.base_url() (kimi-code stays on proxy_url). Security: adversarial review + a systematic token-leak audit found and closed FIVE channels where the primary Kimi token could reach api.x.ai (bearer resolver, api_key stamping, aux summary/classifier/image-describe models, and subagent model-override). Each fix routes through the platform-aware resolver (the oauth model's pooled token or None, NEVER the primary) and is revert-to-red verified. No access/refresh token is ever logged. Registry at 26; picker updated (xai-grok interactive login row); TUI context-window already auto-updates per model. Full gate green (234 suites, fmt, clippy -D warnings, deny). GPT/Claude/Grok officially permit third-party subscription use.
This commit is contained in:
@@ -168,6 +168,21 @@ edges stay deterministic Rust. The harness appends a terminal
|
||||
are built generically from advertised methods (`AuthMethodKind::
|
||||
ApiKeyPlatform`), so new registry rows appear in the picker with no TUI
|
||||
changes.
|
||||
- Refreshable-OAuth providers beyond Kimi Code use a GENERIC device-code
|
||||
(RFC-8628) path, NOT Kimi's bespoke wire. A `uses_oauth` platform carrying
|
||||
`oauth: Some(&OAuthConfig)` (client id / auth host / device+token paths /
|
||||
scope / `scope_key` / optional extra device field) drives
|
||||
`auth::oauth_device` (plain kigi UA, no X-Msh headers) + a scope-keyed
|
||||
`AuthManager::new_oauth_provider` + `refresh::GenericDeviceRefresher`
|
||||
(selected by `build_refresher` via `oauth_config_for_scope_key`). Kimi Code
|
||||
keeps `oauth: None` and its bespoke path unchanged. First such provider:
|
||||
`xai-grok` (`scope_key oauth/xai`, base `api.x.ai/v1`, same wire as the
|
||||
API-key `xai` row) — an INTERACTIVE login row advertised right after
|
||||
`kimi-code` (`AuthMethodKind::OAuthPlatform`). Its `authenticate` arm runs
|
||||
the generic device flow under its own scope; the catalog fetch resolves each
|
||||
such platform's OWN session token (`resolve_generic_oauth_tokens`, refreshed
|
||||
on expiry) and routes `platform.oauth().is_some()` → `platform.base_url()`
|
||||
(kimi-code alone → `proxy_url()`). Tokens are NEVER logged.
|
||||
- Model metadata (context window, thinking levels) comes from the provider
|
||||
wire when served; metadata-poor listings are enriched from models.dev
|
||||
(`kigi-models/src/enrichment.rs` — bundled raw snapshot regenerated by
|
||||
|
||||
Reference in New Issue
Block a user