import * as path from 'path';
import * as os from 'os';
import { fileURLToPath } from 'url';
// Helper to get the project root directory reliably
function getProjectRoot(): string {
const __dirname = path.dirname(fileURLToPath(import.meta.url));
// In build output (e.g., dist/auth/utils.js), __dirname is .../dist/auth
// Go up TWO levels to get the project root
const projectRoot = path.join(__dirname, "..", "..");
return path.resolve(projectRoot);
}
// Returns the configured account ID (for multi-account support)
export function getAccountId(): string | undefined {
return process.env.GOOGLE_DRIVE_ACCOUNT_ID;
}
// Returns the absolute path for the saved token file.
// Uses XDG Base Directory spec with fallback to home directory
// Supports multi-account via GOOGLE_DRIVE_ACCOUNT_ID environment variable
export function getSecureTokenPath(): string {
// Check for custom token path environment variable first (highest priority)
const customTokenPath = process.env.GOOGLE_DRIVE_MCP_TOKEN_PATH;
if (customTokenPath) {
return path.resolve(customTokenPath);
}
// Use XDG Base Directory spec or fallback to ~/.config
const configHome = process.env.XDG_CONFIG_HOME ||
path.join(os.homedir(), '.config');
// Check for account ID (multi-account support)
const accountId = getAccountId();
// If account ID is set, use account-specific directory
// Otherwise, use default directory for backward compatibility
const tokenDir = accountId
? path.join(configHome, 'google-drive-mcp', accountId)
: path.join(configHome, 'google-drive-mcp');
return path.join(tokenDir, 'tokens.json');
}
// Returns the legacy token path for backward compatibility
export function getLegacyTokenPath(): string {
const projectRoot = getProjectRoot();
return path.join(projectRoot, ".gcp-saved-tokens.json");
}
// Additional legacy paths to check
export function getAdditionalLegacyPaths(): string[] {
return [
process.env.GOOGLE_TOKEN_PATH,
path.join(process.cwd(), 'google-tokens.json'),
path.join(process.cwd(), '.gcp-saved-tokens.json')
].filter(Boolean) as string[];
}
// Returns the absolute path for the GCP OAuth keys file with priority:
// 1. Environment variable GOOGLE_DRIVE_OAUTH_CREDENTIALS (highest priority)
// 2. Default file path (lowest priority)
export function getKeysFilePath(): string {
// Priority 1: Environment variable
const envCredentialsPath = process.env.GOOGLE_DRIVE_OAUTH_CREDENTIALS;
if (envCredentialsPath) {
return path.resolve(envCredentialsPath);
}
// Priority 2: Default file path
const projectRoot = getProjectRoot();
const keysPath = path.join(projectRoot, "gcp-oauth.keys.json");
return keysPath;
}
// Interface for OAuth credentials
export interface OAuthCredentials {
client_id: string;
client_secret?: string;
redirect_uris?: string[];
}
// Generate helpful error message for missing credentials
export function generateCredentialsErrorMessage(): string {
const accountId = getAccountId();
const accountInfo = accountId
? `\nAccount ID: ${accountId}`
: '\nAccount ID: (default - no GOOGLE_DRIVE_ACCOUNT_ID set)';
return `
OAuth credentials not found. Please provide credentials using one of these methods:
1. Environment variable:
Set GOOGLE_DRIVE_OAUTH_CREDENTIALS to the path of your credentials file:
export GOOGLE_DRIVE_OAUTH_CREDENTIALS="/path/to/gcp-oauth.keys.json"
2. Default file path:
Place your gcp-oauth.keys.json file in the package root directory.
Token storage:
- Tokens are saved to: ${getSecureTokenPath()}
- To use a custom token location, set GOOGLE_DRIVE_MCP_TOKEN_PATH environment variable
${accountInfo}
Multi-account support:
- Set GOOGLE_DRIVE_ACCOUNT_ID to use separate token storage per account
- Example: GOOGLE_DRIVE_ACCOUNT_ID=work npm run auth
To get OAuth credentials:
1. Go to the Google Cloud Console (https://console.cloud.google.com/)
2. Create or select a project
3. Enable the Google Drive, Docs, Sheets, and Slides APIs
4. Create OAuth 2.0 credentials (Desktop app type)
5. Download the credentials file as gcp-oauth.keys.json
`.trim();
}