msexchange-mcp
Version:
MCP server for Microsoft Exchange/Outlook email operations via Microsoft Graph API
93 lines • 4.03 kB
JavaScript
import { AuthService } from '../auth/authService.js';
import { AuthService as AuthServiceKeyVault } from '../auth/authService-keyvault.js';
import { loadConfig } from '../config/config.js';
// Singleton AuthService instance
let authServiceInstance = null;
function getAuthService() {
if (!authServiceInstance) {
const config = loadConfig();
// Use Key Vault auth service if enabled and configured
if (config.keyVault.enabled && config.keyVault.vaultUri) {
console.error('🔐 Using AuthService with Azure Key Vault integration');
authServiceInstance = new AuthServiceKeyVault(config);
}
else {
console.error('📁 Using standard AuthService (no Key Vault)');
authServiceInstance = new AuthService(config);
// Start proactive token refresh for non-Key Vault version
if ('startProactiveRefresh' in authServiceInstance) {
authServiceInstance.startProactiveRefresh();
}
}
console.error('🔧 Created new AuthService instance');
}
return authServiceInstance;
}
// Helper function to check if an error is token-related
function isTokenError(error) {
return (error?.status === 401 ||
error?.code === 'InvalidAuthenticationToken' ||
error?.code === 'Unauthenticated' ||
error?.message?.includes('authentication') ||
error?.message?.includes('token') ||
error?.message?.includes('unauthorized'));
}
// Enhanced Graph client with automatic token refresh retry
export async function getGraphClientWithRetry(userEmail) {
const maxAttempts = 2;
let lastError;
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
try {
const auth = getAuthService();
console.error(`🔑 Getting token for ${userEmail} (attempt ${attempt}/${maxAttempts})`);
// Force token refresh on retry attempts
const token = attempt > 1
? await auth.forceTokenRefresh(userEmail)
: await auth.getTokenForUser(userEmail);
console.error(`✅ Token acquired successfully`);
return auth.getGraphClient(token);
}
catch (error) {
lastError = error;
console.error(`❌ Token acquisition failed on attempt ${attempt}:`, error.message);
// Only retry if it's a token-related error and we have attempts left
if (isTokenError(error) && attempt < maxAttempts) {
console.error(`🔄 Token error detected, retrying with fresh token...`);
continue;
}
// If not a token error or no attempts left, throw immediately
throw error;
}
}
throw lastError;
}
// Original function maintained for backward compatibility
export async function getGraphClient(userEmail) {
return getGraphClientWithRetry(userEmail);
}
// Function to execute Graph API operations with automatic retry on token errors
export async function executeWithTokenRetry(userEmail, operation) {
const maxAttempts = 2;
let lastError;
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
try {
const client = await getGraphClientWithRetry(userEmail);
return await operation(client);
}
catch (error) {
lastError = error;
console.error(`❌ Graph operation failed on attempt ${attempt}:`, error.message);
// Only retry if it's a token-related error and we have attempts left
if (isTokenError(error) && attempt < maxAttempts) {
console.error(`🔄 Token error detected during operation, retrying...`);
// Clear any cached tokens to force refresh
const auth = getAuthService();
await auth.clearTokenCache(userEmail);
continue;
}
throw error;
}
}
throw lastError;
}
//# sourceMappingURL=graphClient.js.map