M1/F1: Kimi Code OAuth device-code flow
Replace the xAI OAuth stack with the Kimi device authorization grant:
- kimi_oauth.rs wire layer (device_authorization + token poll + refresh
against kigi_env::oauth_host(); client_id per PRD; retryable statuses
429/5xx with backoff; expired_token restarts authorization)
- X-Msh-Device-{Name,Model,Id} headers; device_id minted uuid4-hex at
~/.kigi/device_id (0600)
- Storage: system keyring service `kigi`, entry `oauth/kimi-code`
(macOS/Windows native backends), atomic-file fallback under ~/.kigi;
official client's keyring/~/.kimi never touched
- Refresh manager: 60s tick, threshold max(300, expires_in*0.5),
401-tombstone keyed by rejected refresh token with 300s cooldown and
rotation auto-clear, cross-process lock with sibling-adoption
triple-check, sleep/wake forced refresh
- Deleted xAI machinery: enterprise OIDC (PKCE/JWKS/teams), devbox login,
external auth provider, JWT tier gating + subscription paywall stack,
X-XAI-Token-Auth marker headers, ZDR gates, /user enrichment
- kigi login / TUI /login both drive the device flow; login-host display
now derives from kigi_env::oauth_host()
- 264 auth unit/wiremock tests; live contract probe of
auth.kimi.com/api/oauth/device_authorization matches the wire shapes
Gates: check/clippy --all-targets clean, fmt, deny ok, kigi-shell lib
5131 tests green.
This commit is contained in:
@@ -19,15 +19,10 @@ pub struct CredentialSnapshot {
|
||||
/// identity (`StaticAuthCredentialProvider`). Read by the OTel layer to
|
||||
/// populate the `user.id` resource attribute.
|
||||
pub user_id: Option<String>,
|
||||
/// Team identifier from OAuth. `None` for personal accounts or when
|
||||
/// no auth is configured.
|
||||
pub team_id: Option<String>,
|
||||
/// `uuidv5(NAMESPACE_OID, deployment_key)`, set only for deployment-key auth.
|
||||
pub deployment_id: Option<String>,
|
||||
/// `uuidv5(NAMESPACE_OID, api_key)`, set only for `AuthMode::ApiKey`.
|
||||
pub api_key_id: Option<String>,
|
||||
/// Org id from the OIDC `organizationId` claim; `None` for personal / deployment-key auth.
|
||||
pub organization_id: Option<String>,
|
||||
}
|
||||
|
||||
/// Source of truth for outbound auth on data-collector requests.
|
||||
@@ -50,13 +45,6 @@ pub trait AuthCredentialProvider: HttpAuth + Send + Sync + 'static {
|
||||
/// Returns `false` if no refresher is configured or refresh failed.
|
||||
async fn refresh_after_unauthorized(&self) -> bool;
|
||||
|
||||
/// Whether `X-XAI-Token-Auth` should be sent with the bearer token.
|
||||
/// `false` for deployment keys (bare Bearer), `true` for user/OAuth tokens.
|
||||
/// See `GrokAuthCredentials::apply()` for the wire format contract.
|
||||
fn needs_token_auth_header(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
/// Whether the provider holds a credential worth a real outbound attempt —
|
||||
/// an unexpired token (in memory or on disk), or a static key. Default
|
||||
/// `true` always attempts.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/// Apply auth headers to outbound visibility requests.
|
||||
/// Implemented by `kigi-shell::util::grok_auth_credentials::GrokAuthCredentials`
|
||||
/// Implemented by `kigi-shell::util::kigi_auth_credentials::KigiAuthCredentials`
|
||||
/// to keep credential construction owned by shell while letting data-collector
|
||||
/// build the request without reaching back into shell types.
|
||||
pub trait HttpAuth: Send + Sync {
|
||||
|
||||
Reference in New Issue
Block a user