Skip to main content
Glama

Google Drive MCP Server

by ducla5
auth-middleware.ts5.29 kB
import { AuthManager } from '../types/auth.js'; /** * Authentication middleware for Google Drive API calls * Ensures requests are authenticated and handles token refresh */ export class AuthMiddleware { private authManager: AuthManager; private maxRetries: number; constructor(authManager: AuthManager, maxRetries: number = 3) { this.authManager = authManager; this.maxRetries = maxRetries; } /** * Execute an authenticated API call with automatic retry on auth failure */ async executeWithAuth<T>( apiCall: () => Promise<T>, context: string = 'API call' ): Promise<T> { let lastError: Error | null = null; for (let attempt = 1; attempt <= this.maxRetries; attempt++) { try { // Ensure we're authenticated before making the call if (!this.authManager.isAuthenticated()) { const authSuccess = await this.authManager.authenticate(); if (!authSuccess) { throw new Error('Authentication failed'); } } // Execute the API call return await apiCall(); } catch (error) { lastError = error instanceof Error ? error : new Error(String(error)); // Check if this is an authentication error if (this.isAuthError(error)) { console.warn(`Authentication error on attempt ${attempt} for ${context}:`, lastError.message); // Try to refresh token if not on last attempt if (attempt < this.maxRetries) { const refreshSuccess = await this.authManager.refreshToken(); if (refreshSuccess) { console.log(`Token refreshed successfully, retrying ${context}`); continue; } else { console.error(`Token refresh failed for ${context}`); } } } else { // Non-auth error, don't retry throw lastError; } } } // All retries exhausted throw new AuthenticationError( `Authentication failed after ${this.maxRetries} attempts for ${context}`, lastError ); } /** * Validate current authentication status */ async validateAuth(): Promise<AuthValidationResult> { try { if (!this.authManager.isAuthenticated()) { return { isValid: false, error: 'Not authenticated', needsReauth: true }; } // Try to get access token to verify it's available const token = this.authManager.getAccessToken(); if (!token) { return { isValid: false, error: 'No access token available', needsReauth: true }; } return { isValid: true, error: null, needsReauth: false }; } catch (error) { return { isValid: false, error: error instanceof Error ? error.message : 'Unknown error', needsReauth: true }; } } /** * Check if an error is authentication-related */ private isAuthError(error: any): boolean { if (!error) return false; // Check error message patterns const errorMessage = error.message?.toLowerCase() || ''; const authErrorPatterns = [ 'unauthorized', 'invalid_token', 'token_expired', 'authentication', 'invalid credentials', 'access denied', '401' ]; if (authErrorPatterns.some(pattern => errorMessage.includes(pattern))) { return true; } // Check HTTP status codes if (error.status === 401 || error.code === 401) { return true; } // Check Google API specific error codes if (error.code === 'UNAUTHENTICATED' || error.code === 'PERMISSION_DENIED') { return true; } return false; } /** * Create a wrapper function that automatically handles authentication */ createAuthenticatedWrapper<TArgs extends any[], TReturn>( fn: (...args: TArgs) => Promise<TReturn>, context?: string ): (...args: TArgs) => Promise<TReturn> { return async (...args: TArgs): Promise<TReturn> => { return this.executeWithAuth( () => fn(...args), context || fn.name || 'wrapped function' ); }; } } /** * Custom error class for authentication failures */ export class AuthenticationError extends Error { public readonly originalError: Error | null; constructor(message: string, originalError: Error | null = null) { super(message); this.name = 'AuthenticationError'; this.originalError = originalError; } } /** * Result of authentication validation */ export interface AuthValidationResult { isValid: boolean; error: string | null; needsReauth: boolean; } /** * Utility function to create authenticated API client wrapper */ export function createAuthenticatedClient<T>( client: T, authMiddleware: AuthMiddleware ): T { const wrapper = {} as T; // Wrap all methods of the client with authentication for (const key in client) { const value = client[key]; if (typeof value === 'function') { (wrapper as any)[key] = authMiddleware.createAuthenticatedWrapper( value.bind(client), `${String(key)} method` ); } else { (wrapper as any)[key] = value; } } return wrapper; }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/ducla5/gdriver-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server