/** * Loopback OAuth Implementation (RFC 8252) * * Implements OAuth 2.0 Authorization Code Flow with PKCE using loopback interface redirection. * Uses ephemeral local server with OS-assigned port (RFC 8252 Section 8.3). * * CHANGE (2026-01-03): * - Non-headless mode now opens the auth URL AND blocks (polls) until tokens are available, * for BOTH redirectUri (persistent) and ephemeral (loopback) modes. * - Ephemeral flow no longer calls `open()` itself. Instead it: * 1) starts the loopback callback server * 2) throws AuthRequiredError(auth_url) * - Middleware catches AuthRequiredError(auth_url): * - if not headless: open(url) once + poll pending state until callback completes (or timeout) * - then retries token acquisition and injects authContext in the SAME tool call. */ import { type OAuth2TokenStorageProvider } from '@mcp-z/oauth'; import { OAuth2Client } from 'google-auth-library'; import { type CachedToken, type LoopbackOAuthConfig } from '../types.js'; /** * Loopback OAuth Client (RFC 8252 Section 7.3) * * Implements OAuth 2.0 Authorization Code Flow with PKCE for native applications * using loopback interface redirection. Manages ephemeral OAuth flows and token persistence * with Keyv for key-based token storage using compound keys. * * Token key format: {accountId}:{service}:token (e.g., "user@example.com:gmail:token") */ export declare class LoopbackOAuthProvider implements OAuth2TokenStorageProvider { private config; private openedStates; constructor(config: LoopbackOAuthConfig); /** * Get access token from Keyv using compound key * * @param accountId - Account identifier (email address). Required for loopback OAuth. * @returns Access token for API requests */ getAccessToken(accountId?: string): Promise; /** * Convert to googleapis-compatible OAuth2Client * * @param accountId - Account identifier for multi-account support (e.g., 'user@example.com') * @returns OAuth2Client configured for the specified account */ toAuth(accountId?: string): OAuth2Client; /** * Get user email from Google's userinfo endpoint (pure query) * Used to query email for existing authenticated account * * @param accountId - Account identifier to get email for * @returns User's email address */ getUserEmail(accountId?: string): Promise; private isTokenValid; /** * Fetch user email from Google OAuth2 userinfo endpoint * Called during OAuth flow to get email for accountId * * @param accessToken - Fresh access token from OAuth exchange * @returns User's email address */ private fetchUserEmailFromToken; /** * Build OAuth authorization URL with the "most parameters" baseline. * This is shared by BOTH persistent (redirectUri) and ephemeral (loopback) modes. */ private buildAuthUrl; /** * Create a cached token + email from an authorization code. * This is the shared callback handler for BOTH persistent and ephemeral modes. */ private handleAuthorizationCode; /** * Store token + account metadata. Shared by BOTH persistent and ephemeral modes. */ private persistAuthResult; /** * Pending auth (PKCE verifier) key format. * Keep as-is (confirmed), even though it's not a public contract. */ private pendingKey; /** * Store PKCE verifier for callback (5 minute TTL). * Shared by BOTH persistent and ephemeral modes. */ private createPendingAuth; /** * Load and validate pending auth state (5 minute TTL). * Shared by BOTH persistent and ephemeral modes. */ private readAndValidatePendingAuth; /** * Mark pending auth as completed (used by middleware polling). */ private markPendingComplete; /** * Clean up pending auth state. */ private deletePendingAuth; /** * Wait until pending auth is marked completed (or timeout). * Used by middleware after opening auth URL in non-headless mode. */ private waitForOAuthCompletion; /** * Process an OAuth callback using shared state validation + token exchange + persistence. * Used by BOTH: * - ephemeral loopback server callback handler * - persistent redirectUri callback handler * * IMPORTANT CHANGE: * - We do NOT delete pending state here anymore. * - We mark it completed so middleware can poll and then clean it up. */ private processOAuthCallback; /** * Loopback OAuth server helper (RFC 8252 Section 7.3) * * Implements ephemeral local server with OS-assigned port (RFC 8252 Section 8.3). * Shared callback handling uses: * - the same authUrl builder as redirectUri mode * - the same pending PKCE verifier storage as redirectUri mode * - the same callback processor as redirectUri mode */ private createOAuthCallbackServer; /** * Starts the ephemeral loopback server and returns an AuthRequiredError(auth_url). * Middleware will open+poll and then retry in the same call. */ private startEphemeralOAuthFlow; private exchangeCodeForToken; private refreshAccessToken; /** * Handle OAuth callback from persistent endpoint. * Used by HTTP servers with configured redirectUri. * * @param params - OAuth callback parameters * @returns Email and cached token */ handleOAuthCallback(params: { code: string; state?: string; }): Promise<{ email: string; token: CachedToken; }>; /** * Create authentication middleware for MCP tools, resources, and prompts * * Returns position-aware middleware wrappers that enrich handlers with authentication context. * The middleware handles token retrieval, refresh, and AuthRequiredError automatically. * * Single-user middleware for desktop/CLI apps where ONE user runs the entire process: * - Desktop applications (Claude Desktop) * - CLI tools (Gmail CLI) * - Personal automation scripts * * All requests use token lookups based on the active account or account override. * * @returns Object with withToolAuth, withResourceAuth, withPromptAuth methods */ authMiddleware(): { withToolAuth: (module: T) => T; withResourceAuth: (module: T) => T; withPromptAuth: (module: T) => T; }; } /** * Create a loopback OAuth client for Google services * Works for both stdio and HTTP transports */ export declare function createGoogleFileAuth(config: LoopbackOAuthConfig): OAuth2TokenStorageProvider;