# How to Set Up OAuth Authentication with Keyring Storage in Kimi Code

> Securely set up OAuth authentication with keyring storage in Kimi Code. Learn how Kimi Code uses native OS keychains for token storage, enhancing security.

- Repository: [Moonshot AI/kimi-code](https://github.com/MoonshotAI/kimi-code)
- Tags: how-to-guide
- Published: 2026-07-26

---

**Kimi Code implements a modular OAuth subsystem that securely stores access tokens in your operating system's native keyring—such as macOS Keychain, Windows Credential Manager, or Linux Secret Service—or falls back to hardened file storage with strict 0600 permissions.**

The MoonshotAI/kimi-code repository provides a TypeScript-based OAuth implementation designed for secure credential management across platforms. Whether you are building CLI tools or IDE extensions, understanding how to configure **OAuth authentication with keyring storage in Kimi Code** ensures your users' access tokens remain encrypted at rest and protected from unauthorized access.

## Core Components of the OAuth System

The OAuth implementation in Kimi Code centers on five primary components that coordinate authentication flows and secure storage. These modules handle everything from browser-based login initiation to atomic token persistence.

### The OAuth Facade

The **`OAuth`** class in [`packages/oauth/src/oauth.ts`](https://github.com/MoonshotAI/kimi-code/blob/main/packages/oauth/src/oauth.ts) serves as the high-level entry point. It initiates browser-based login flows, exchanges authorization codes for tokens, and exposes a simplified API with three main methods: `login(scopes)`, `refresh(name)`, and `revoke(name)`.

### Token Storage Implementations

Kimi Code provides two interchangeable storage backends implementing the `TokenStorage` interface:

- **`FileTokenStorage`** ([`packages/oauth/src/storage.ts`](https://github.com/MoonshotAI/kimi-code/blob/main/packages/oauth/src/storage.ts)): Persists tokens as JSON files under `~/.kimi-code/credentials/` with atomic writes and `0600` file permissions.
- **`KeyringTokenStorage`** ([`packages/oauth/src/keyring.ts`](https://github.com/MoonshotAI/kimi-code/blob/main/packages/oauth/src/keyring.ts)): Stores the same JSON payload in the OS-native keyring via the `KeyringAdapter`, avoiding plain-file exposure entirely.

### Lifecycle and State Management

The **`OAuthManager`** class ([`packages/oauth/src/oauth-manager.ts`](https://github.com/MoonshotAI/kimi-code/blob/main/packages/oauth/src/oauth-manager.ts)) coordinates token lifecycles, manages in-memory caching, and handles concurrent refresh operations across processes. It leverages **`TokenState`** ([`packages/oauth/src/token-state.ts`](https://github.com/MoonshotAI/kimi-code/blob/main/packages/oauth/src/token-state.ts)) to track expiry windows and determine when background refreshes are necessary using the `isExpired()` and `needsRefresh()` helpers.

## Setting Up Basic OAuth with File Storage

For development environments or systems without a native keyring, configure the `OAuth` instance with `FileTokenStorage`. This implementation guarantees atomic writes and strict directory permissions.

```typescript
import { OAuth, FileTokenStorage } from '@moonshot-ai/kimi-code/oauth';

const credDir = `${process.env.HOME}/.kimi-code/credentials`;
const storage = new FileTokenStorage(credDir);

const oauth = new OAuth({
  clientId: 'YOUR_CLIENT_ID',
  clientSecret: 'YOUR_CLIENT_SECRET',
  redirectUri: 'http://localhost:3000/callback',
  storage,
});

await oauth.login(['read', 'write']);

```

The `FileTokenStorage` constructor accepts a directory path where it creates individual JSON files for each token set, ensuring data is never written partially to disk.

## Configuring OS Keyring Storage

To store credentials in the operating system's secure keyring instead of plain files, instantiate `KeyringTokenStorage`. This adapter automatically detects and uses macOS Keychain, Windows Credential Manager, or Linux Secret Service.

```typescript
import { OAuth, KeyringTokenStorage } from '@moonshot-ai/kimi-code/oauth';

const storage = new KeyringTokenStorage();
const oauth = new OAuth({
  clientId: 'YOUR_CLIENT_ID',
  clientSecret: 'YOUR_CLIENT_SECRET',
  redirectUri: 'http://localhost:3000/callback',
  storage,
});

await oauth.login(['read']);

```

When the platform supports a native keyring, this configuration prevents tokens from ever touching the filesystem unencrypted, satisfying strict security compliance requirements.

## Token Lifecycle Management

### Automatic Retrieval and Refresh

After authentication, retrieve tokens using `oauth.getToken(name)`. The `OAuthManager` automatically checks `TokenState.needsRefresh()` before returning the token, triggering background refreshes when the access token approaches expiry.

```typescript
async function callKimiAPI() {
  const token = await oauth.getToken('default');
  if (!token) throw new Error('User not authenticated');

  const response = await fetch('https://api.kimi.ai/v1/resource', {
    headers: { Authorization: `Bearer ${token.accessToken}` },
  });
  return response.json();
}

```

### Concurrent Safety Mechanisms

Because multiple processes may attempt simultaneous token refreshes, `OAuthManager` implements a file-based locking strategy. It creates a `<name>.lock` file in the credentials directory. If a process cannot obtain the lock, it waits for the active refresh to complete, preventing race conditions and token invalidation storms.

### Manual Refresh and Revocation

Force an immediate token refresh—useful when you know the refresh window has passed:

```typescript
await oauth.refresh('default');

```

To invalidate tokens both locally and on the authorization server:

```typescript
await oauth.revoke('default');

```

The `revoke()` method contacts the Kimi Code token endpoint to invalidate the credentials, then calls `storage.remove(name)` to delete the local keyring entry or JSON file.

## Data Validation and Type Safety

All token interactions use Zod-validated contracts defined in [`packages/oauth/src/types.ts`](https://github.com/MoonshotAI/kimi-code/blob/main/packages/oauth/src/types.ts). The `TokenInfoWire` schema ensures that corrupted data never propagates into the runtime, with conversion helpers `tokenFromWire()` and `tokenToWire()` handling serialization between the storage layer and the internal `TokenState` model.

## Summary

- **Kimi Code** provides a dual-storage OAuth system supporting both OS keyrings and hardened file storage via the `TokenStorage` interface.
- Use **`KeyringTokenStorage`** ([`packages/oauth/src/keyring.ts`](https://github.com/MoonshotAI/kimi-code/blob/main/packages/oauth/src/keyring.ts)) for production deployments requiring OS-level encryption, or **`FileTokenStorage`** ([`packages/oauth/src/storage.ts`](https://github.com/MoonshotAI/kimi-code/blob/main/packages/oauth/src/storage.ts)) with `0600` permissions for universal compatibility.
- The **`OAuthManager`** handles concurrent refreshes safely using lock files and validates token state using `TokenState.needsRefresh()`.
- All data passing through the system is validated against `TokenInfoWire` schemas to prevent corruption.

## Frequently Asked Questions

### What happens if the OS keyring is unavailable?

If `KeyringTokenStorage` cannot access the native keyring service, the constructor will throw an initialization error. For environments without keyring support, fall back to `FileTokenStorage`, which stores tokens under `~/.kimi-code/credentials/` with atomic writes and strict `0600` permissions, ensuring credentials remain readable only by the current user.

### How does Kimi Code prevent race conditions during token refresh?

The `OAuthManager` class implements a cross-process locking mechanism using lock files in the credentials directory. When one process initiates a refresh, it acquires `<name>.lock`; subsequent processes detecting this lock wait for the operation to complete rather than triggering duplicate refresh requests, preventing token invalidation.

### Can I migrate existing tokens from file storage to keyring storage?

Migration is supported by instantiating both storage classes and transferring the token data. Read the existing token from `FileTokenStorage`, then persist it using `KeyringTokenStorage.save(name, token)`. Once verified, remove the file-based credential with `FileTokenStorage.remove(name)` to complete the migration.

### What permissions does the file-based storage use?

`FileTokenStorage` in [`packages/oauth/src/storage.ts`](https://github.com/MoonshotAI/kimi-code/blob/main/packages/oauth/src/storage.ts) creates directories with `0700` permissions and token files with `0600` permissions, ensuring that only the owning user can read or write credential files. All write operations are atomic, using temporary files and renames to prevent corruption during system crashes.