How to Set Up OAuth with Kimi-Code: A Complete Implementation Guide

Set up OAuth with Kimi-Code by configuring the OAuth host, instantiating KimiOAuthToolkit, and running the device-code flow through toolkit.login() — the SDK handles token persistence, automatic refresh, and cross-process locking automatically.

The @moonshot-ai/kimi-code SDK includes a self-contained OAuth implementation that eliminates external dependencies. This guide walks through the complete setup process using the actual source architecture from the MoonshotAI/kimi-code repository, covering configuration, authentication flows, token management, and Kimi-specific API integration.

OAuth Architecture Overview

Kimi-Code's OAuth system consists of three coordinated components:

Component Responsibility Source Location
Flow Configuration Defines OAuth host and client parameters [packages/oauth/src/constants.ts](https://github.com/MoonshotAI/kimi-code/blob/main/packages/oauth/src/constants.ts)
OAuthManager Token storage, refresh, device-code orchestration, file locking [packages/oauth/src/oauth-manager.ts](https://github.com/MoonshotAI/kimi-code/blob/main/packages/oauth/src/oauth-manager.ts)
KimiOAuthToolkit High-level façade with login/logout/status methods and Kimi API helpers [packages/oauth/src/toolkit.ts](https://github.com/MoonshotAI/kimi-code/blob/main/packages/oauth/src/toolkit.ts)

Step 1: Configure the OAuth Host (Optional)

By default, Kimi-Code connects to https://auth.kimi.com. For private deployments, set either environment variable before importing the SDK:

export KIMI_CODE_OAUTH_HOST="https://my-kimi-instance.com"

# Legacy fallback also supported:

export KIMI_OAUTH_HOST="https://my-kimi-instance.com"

The KIMI_CODE_FLOW_CONFIG constant in constants.ts (lines 5-19) reads these variables and constructs the flow configuration. If neither variable is set, the SDK falls back to the production Kimi auth server.

Step 2: Create a KimiOAuthToolkit Instance

The KimiOAuthToolkit class is the primary entry point for OAuth with Kimi-Code. Instantiate it with defaults or custom options:

import { KimiOAuthToolkit } from '@moonshot-ai/kimi-code/oauth';

// Default: stores tokens at ~/.kimi-code/credentials
const toolkit = new KimiOAuthToolkit();

For custom storage locations:

import { KimiOAuthToolkit } from '@moonshot-ai/kimi-code/oauth';
import { join } from 'node:path';
import { homedir } from 'node:os';

const toolkit = new KimiOAuthToolkit({
  homeDir: join(homedir(), '.my-kimi')
});

The constructor accepts homeDir, custom fetch implementations for non-Node environments, and other storage configurations.

Step 3: Execute the Device-Code Login Flow

Call toolkit.login() to initiate the OAuth Device Code flow. This opens a browser for user authorization and handles polling automatically:

async function authenticate() {
  const toolkit = new KimiOAuthToolkit();
  
  const result = await toolkit.login(); // provider defaults to "kimi-code"
  console.log('Authenticated with provider:', result.providerName);
}

authenticate().catch(console.error);

The underlying OAuthManager orchestrates three phases defined in packages/oauth/src/oauth.ts:

  1. Request device code — requestDeviceAuthorization() creates user_code and verification_uri_complete (lines 19-58)
  2. Poll token endpoint — pollDeviceToken() checks status until success, denied, expired, or pending (lines 68-111)
  3. Token refresh — refreshAccessToken() exchanges refresh tokens (lines 126-190)

Custom Device Code Display

Override the default browser-opening behavior with the onDeviceCode hook:

await toolkit.login(undefined, {
  onDeviceCode: async (auth) => {
    console.log(`Enter code ${auth.userCode} at ${auth.verificationUriComplete}`);
    // Custom: send to Slack, display in UI, etc.
  }
});

Step 4: Obtain and Use Access Tokens

The toolkit provides two token retrieval patterns for OAuth with Kimi-Code:

Direct Token Access

const token = await toolkit.getCachedAccessToken();
// Returns string or undefined; does NOT refresh automatically

BearerTokenProvider (Auto-Refreshing)

For long-running applications, use the provider that automatically refreshes:

const bearer = toolkit.tokenProvider(); // KimiOAuthToolkit.tokenProvider()

async function callProtectedApi(url: string) {
  const token = await bearer.getAccessToken(); // Triggers OAuthManager.ensureFresh()
  const response = await fetch(url, {
    headers: { Authorization: `Bearer ${token}` }
  });
  return response.json();
}

The ensureFresh() method in oauth-manager.ts (lines 54-82) checks token expiration and triggers refresh when within the renewal window.

Step 5: Logout and Credential Cleanup

Remove stored tokens and provisioned configuration:

await toolkit.logout();
// Deletes token file via OAuthManager.logout() (oauth-manager.ts lines 46-48)

Verify removal:

const cached = await toolkit.getCachedAccessToken();
console.log(cached); // undefined

Step 6: Access Kimi-Specific APIs

The toolkit wraps Kimi-managed endpoints for usage, user info, and feedback:

// Fetch usage quota and limits
const usage = await toolkit.getManagedUsage();

if (usage.kind === 'ok') {
  console.log('Limits:', usage.limits);
  console.log('Current usage:', usage.current);
} else {
  console.error('Failed:', usage.message);
}

These methods use fetchManagedUsage and related helpers in src/managed-usage.ts, automatically injecting the bearer token from your OAuth session.

Complete Working Examples

Example 1: Full Login and Token Display

import { KimiOAuthToolkit } from '@moonshot-ai/kimi-code/oauth';

async function main() {
  const toolkit = new KimiOAuthToolkit();

  await toolkit.login(undefined, {
    onDeviceCode: (auth) => {
      console.log(`🔑 Code: ${auth.userCode}`);
      console.log(`🌐 Visit: ${auth.verificationUriComplete}`);
    }
  });

  const token = await toolkit.getCachedAccessToken();
  console.log('Access token:', token);
}

main().catch(console.error);

Example 2: Auto-Refreshing API Client

import { KimiOAuthToolkit } from '@moonshot-ai/kimi-code/oauth';

async function queryKimiApi() {
  const toolkit = new KimiOAuthToolkit();
  const bearer = toolkit.tokenProvider();

  const response = await fetch('https://api.kimi.com/v1/user', {
    headers: {
      Authorization: `Bearer ${await bearer.getAccessToken()}`
    }
  });
  
  const userData = await response.json();
  console.log('User:', userData);
}

queryKimiApi().catch(console.error);

Example 3: Session Cleanup

import { KimiOAuthToolkit } from '@moonshot-ai/kimi-code/oauth';

async function cleanup() {
  const toolkit = new KimiOAuthToolkit();
  
  await toolkit.logout();
  const remaining = await toolkit.getCachedAccessToken();
  
  console.assert(remaining === undefined, 'Token should be removed');
  console.log('Logout successful');
}

cleanup().catch(console.error);

Source File Reference

Understanding these files deepens your ability to customize OAuth with Kimi-Code:

File Purpose
[constants.ts](https://github.com/MoonshotAI/kimi-code/blob/main/packages/oauth/src/constants.ts) OAuth host configuration, environment variable parsing
[types.ts](https://github.com/MoonshotAI/kimi-code/blob/main/packages/oauth/src/types.ts) TypeScript interfaces for tokens, flows, and responses
[oauth.ts](https://github.com/MoonshotAI/kimi-code/blob/main/packages/oauth/src/oauth.ts) HTTP layer: device authorization, token polling, refresh
[oauth-manager.ts](https://github.com/MoonshotAI/kimi-code/blob/main/packages/oauth/src/oauth-manager.ts) Core lifecycle: storage, refresh, locking, flow coordination
[toolkit.ts](https://github.com/MoonshotAI/kimi-code/blob/main/packages/oauth/src/toolkit.ts) Public API façade combining manager with Kimi helpers
[storage.ts](https://github.com/MoonshotAI/kimi-code/blob/main/packages/oauth/src/storage.ts) FileTokenStorage default implementation
[token-state.ts](https://github.com/MoonshotAI/kimi-code/blob/main/packages/oauth/src/token-state.ts) Token validity classification helpers

Summary

  • Configure the OAuth host via KIMI_CODE_OAUTH_HOST for private deployments, or use the default https://auth.kimi.com
  • Instantiate KimiOAuthToolkit with optional homeDir and custom fetch for your environment
  • Authenticate with toolkit.login() using the device-code flow; customize display via onDeviceCode
  • Retrieve tokens through getCachedAccessToken() or tokenProvider().getAccessToken() for auto-refresh
  • Call APIs by passing the bearer token in Authorization headers; use toolkit helpers for Kimi endpoints
  • Logout with toolkit.logout() to clear credentials from ~/.kimi-code/credentials

Frequently Asked Questions

Does Kimi-Code support OAuth refresh tokens?

Yes. The OAuthManager automatically refreshes access tokens using refreshAccessToken() in oauth.ts (lines 126-190). The BearerTokenProvider calls ensureFresh() before every token retrieval, so your code never handles expired tokens manually.

Can I use Kimi-Code OAuth in browser environments?

Partially. The default FileTokenStorage requires Node.js filesystem access. Pass a custom storage implementation and inject a browser-compatible fetch via the KimiOAuthToolkit constructor options to adapt for non-Node runtimes.

Where are tokens stored on disk?

By default, in ~/.kimi-code/credentials/ as JSON files with cross-process file locking. Change this path via the homeDir constructor option. The storage format and locking mechanism are implemented in storage.ts and coordinated through oauth-manager.ts.

What OAuth flows does Kimi-Code support?

The SDK implements the OAuth 2.0 Device Authorization Grant (RFC 8628) exclusively. This flow is optimized for CLI tools and devices without browsers. The requestDeviceAuthorization() and pollDeviceToken() functions in oauth.ts handle the complete flow; no authorization code or PKCE flows are currently implemented.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →