How to Set Up OAuth Authentication with Keyring Storage in Kimi Code
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 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): Persists tokens as JSON files under~/.kimi-code/credentials/with atomic writes and0600file permissions.KeyringTokenStorage(packages/oauth/src/keyring.ts): Stores the same JSON payload in the OS-native keyring via theKeyringAdapter, avoiding plain-file exposure entirely.
Lifecycle and State Management
The OAuthManager class (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) 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.
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.
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.
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:
await oauth.refresh('default');
To invalidate tokens both locally and on the authorization server:
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. 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
TokenStorageinterface. - Use
KeyringTokenStorage(packages/oauth/src/keyring.ts) for production deployments requiring OS-level encryption, orFileTokenStorage(packages/oauth/src/storage.ts) with0600permissions for universal compatibility. - The
OAuthManagerhandles concurrent refreshes safely using lock files and validates token state usingTokenState.needsRefresh(). - All data passing through the system is validated against
TokenInfoWireschemas 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 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.
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →