@juspay/neurolink
Version:
Universal AI Development Platform with working MCP integration, multi-provider support, voice (TTS/STT/realtime), and professional CLI. 58+ external MCP servers discoverable, multimodal file processing, RAG pipelines. Build, test, and deploy AI applicatio
271 lines (270 loc) • 9.77 kB
TypeScript
/**
* NeuroLink OAuth Token Store
*
* Secure storage for OAuth tokens with encoding support and multi-provider capability.
* Stores tokens in the user's home directory with restrictive permissions.
*
* Features:
* - Multi-provider token storage in a single tokens.json file
* - Secure file storage with 0o600 permissions
* - Token expiration checking with configurable buffer
* - Simple XOR-based obfuscation (not encryption, but not plaintext)
* - Automatic token refresh via configurable refresher functions
* - Cross-platform support (Unix/macOS/Windows)
*/
import type { StoredOAuthTokens, TokenRefresher } from "../types/index.js";
/**
* Secure token storage for OAuth tokens with multi-provider support
*
* Provides persistent storage for OAuth tokens with:
* - Multi-provider support in a single file
* - Secure file permissions (0o600)
* - Optional obfuscation/encoding
* - Token expiration checking with buffer
* - Automatic token refresh via configurable refreshers
*
* @example
* ```typescript
* const store = new TokenStore();
*
* // Save tokens for a provider
* await store.saveTokens("anthropic", {
* accessToken: "sk-...",
* refreshToken: "rt-...",
* expiresAt: Date.now() + 3600000,
* tokenType: "Bearer",
* });
*
* // Set up automatic refresh
* store.setTokenRefresher("anthropic", async (refreshToken) => {
* // Call OAuth refresh endpoint
* return newTokens;
* });
*
* // Get a valid token (auto-refreshes if needed)
* const token = await store.getValidToken("anthropic");
* ```
*/
export declare class TokenStore {
private static readonly STORAGE_VERSION;
private static readonly NEUROLINK_DIR;
private static readonly TOKEN_FILE;
private static readonly FILE_PERMISSIONS;
private static readonly DIR_PERMISSIONS;
/** Default expiration buffer: 1 hour (proactive refresh before actual expiry) */
private static readonly DEFAULT_EXPIRY_BUFFER_MS;
private readonly storagePath;
private readonly encryptionEnabled;
private readonly encryptionKey;
private readonly tokenRefreshers;
private readonly inFlightRefreshes;
private readonly _mutex;
/**
* Creates a new TokenStore instance
*
* @param options - Configuration options
* @param options.encryptionEnabled - Whether to enable token obfuscation (default: true)
* @param options.customStoragePath - Override the default storage path
*/
constructor(options?: {
encryptionEnabled?: boolean;
customStoragePath?: string;
});
/**
* Gets the path where tokens are stored
*
* @returns The absolute path to the token storage file
*/
getStoragePath(): string;
/**
* Saves OAuth tokens for a specific provider
*
* @param provider - The provider name (e.g., "anthropic", "openai")
* @param tokens - The OAuth tokens to save
* @throws TokenStoreError if storage fails
*/
saveTokens(provider: string, tokens: StoredOAuthTokens): Promise<void>;
/**
* Internal save without mutex — callers must already hold the mutex.
*/
private _saveTokensInternal;
/**
* Loads stored OAuth tokens for a specific provider
*
* @param provider - The provider name (e.g., "anthropic", "openai")
* @returns The stored tokens, or null if not found
* @throws TokenStoreError if reading fails (other than file not found)
*/
loadTokens(provider: string): Promise<StoredOAuthTokens | null>;
/**
* Internal load without mutex — callers must already hold the mutex.
*/
private _loadTokensInternal;
/**
* Clears stored tokens for a specific provider
*
* @param provider - The provider name (e.g., "anthropic", "openai")
* @throws TokenStoreError if deletion fails
*/
clearTokens(provider: string): Promise<void>;
private _clearTokensImpl;
/**
* Checks if the given tokens are expired
*
* @param tokens - The OAuth tokens to check
* @param bufferMs - Buffer time in milliseconds before actual expiration (default: 5 minutes)
* @returns true if token is expired or will expire within buffer time
*/
isTokenExpired(tokens: StoredOAuthTokens, bufferMs?: number): boolean;
/**
* Gets a valid access token for a provider, refreshing if needed
*
* If the stored token is expired or about to expire, and a refresher
* function has been set, it will automatically refresh the token.
*
* @param provider - The provider name (e.g., "anthropic", "openai")
* @returns The valid access token, or null if not available
* @throws TokenStoreError if refresh fails
*/
getValidToken(provider: string): Promise<string | null>;
private _getValidTokenImpl;
/**
* Sets the token refresher function for a provider
*
* The refresher function will be called automatically when getValidToken
* detects that the stored token is expired or about to expire.
*
* @param provider - The provider name (e.g., "anthropic", "openai")
* @param refresher - Function that takes a refresh token and returns new tokens
*/
setTokenRefresher(provider: string, refresher: TokenRefresher): void;
/**
* Removes the token refresher function for a provider
*
* @param provider - The provider name (e.g., "anthropic", "openai")
*/
clearTokenRefresher(provider: string): void;
/**
* Checks if tokens exist for a specific provider
*
* @param provider - The provider name (e.g., "anthropic", "openai")
* @returns true if tokens are stored for the provider
*/
hasTokens(provider: string): Promise<boolean>;
/**
* Lists all providers that have stored tokens
*
* @returns Array of provider names
*/
listProviders(): Promise<string[]>;
/**
* Lists all provider keys that start with the given prefix
*
* @param prefix - The prefix to filter by (e.g., "anthropic:")
* @returns Array of matching provider keys
*/
listByPrefix(prefix: string): Promise<string[]>;
/**
* Marks a provider's tokens as permanently disabled (persisted to disk).
*
* Disabled accounts are skipped immediately by consumers — no wasted
* round-trips. The state survives proxy restarts because it is stored
* alongside the tokens in the JSON file.
*
* @param provider - The provider key (e.g., "anthropic:user@example.com")
* @param reason - Optional human-readable reason (e.g., "refresh_failed")
*/
markDisabled(provider: string, reason?: string): Promise<void>;
/**
* Re-enables a previously disabled provider (persisted to disk).
*
* Clears the disabled flag, timestamp, and reason so the account can
* be used again by the proxy pool.
*
* @param provider - The provider key (e.g., "anthropic:user@example.com")
*/
markEnabled(provider: string): Promise<void>;
/**
* Checks whether a provider's tokens are currently disabled.
*
* Returns false for providers that don't exist in the store (no tokens
* at all) and for entries that predate the disabled field (backward compat).
*
* @param provider - The provider key
* @returns true if the provider entry exists and is disabled
*/
isDisabled(provider: string): Promise<boolean>;
/**
* Lists all provider keys that are currently disabled.
*
* @returns Array of disabled provider keys (empty if none or no storage file)
*/
listDisabled(): Promise<string[]>;
/**
* Removes expired and unrefreshable token entries from disk.
*
* An entry is pruned when:
* - Its access token is expired (with optional buffer) AND it has no
* refresh token, AND it is NOT manually disabled.
*
* Manually disabled entries are preserved so that `auth enable` can
* re-enable them later. They are only removed via explicit `clearTokens`.
*
* @param bufferMs - Extra buffer in milliseconds to subtract from expiresAt
* when checking expiry (default: 0 — strict expiry check)
* @returns Array of provider keys that were removed
*/
pruneExpired(bufferMs?: number): Promise<string[]>;
/**
* Clears all stored tokens for all providers
*
* @throws TokenStoreError if deletion fails
*/
clearAllTokens(): Promise<void>;
/**
* Loads the storage data from file
*/
private loadStorageData;
/**
* Saves storage data to file
*/
private saveStorageData;
/**
* Deletes the storage file
*/
private deleteStorageFile;
/**
* Validates token structure
*/
private validateTokens;
/**
* Ensures the storage directory exists with proper permissions
*/
private ensureDirectory;
/**
* Derives an encoding key from machine-specific information
* This provides basic obfuscation - for production use, consider
* using proper encryption with a user-provided key or system keychain
*/
private deriveEncryptionKey;
/**
* Simple XOR-based obfuscation
* Note: This is NOT cryptographically secure, just basic obfuscation
* For production use, consider using node:crypto with proper encryption
*/
private obfuscate;
/**
* Reverses the XOR obfuscation
*/
private deobfuscate;
}
/**
* Default token store singleton instance
* Uses default configuration with encryption enabled
*/
export declare const tokenStore: TokenStore;
/**
* Alias for backward compatibility
* @deprecated Use tokenStore instead
*/
export declare const defaultTokenStore: TokenStore;