/** * GitHub authentication manager using OAuth device flow * Handles authentication for MCP servers without requiring client secrets */ import { TokenManager } from '../security/tokenManager.js'; import { APICache } from '../cache/APICache.js'; import { ConfigManager } from '../config/ConfigManager.js'; export interface DeviceCodeResponse { device_code: string; user_code: string; verification_uri: string; expires_in: number; interval: number; } export interface TokenResponse { access_token: string; token_type: string; scope: string; } export interface AuthStatus { isAuthenticated: boolean; hasToken: boolean; username?: string; scopes?: string[]; expiresAt?: Date; } /** * Manages GitHub authentication using the OAuth device flow * This is the recommended approach for CLI/desktop applications */ export declare class GitHubAuthManager { /** * DollhouseMCP's official OAuth App Client ID * This is PUBLIC information - OAuth Client IDs are meant to be visible. * Only Client Secrets are private (device flow doesn't use secrets). * * This Client ID enables the GitHub device flow authentication * allowing users to authenticate with an 8-character code. */ private static readonly DEFAULT_CLIENT_ID; private readonly DEVICE_CODE_URL; private readonly TOKEN_URL; private readonly USER_URL; private readonly DEFAULT_POLL_INTERVAL; private readonly MAX_POLL_ATTEMPTS; private readonly configManager; private apiCache; private activePolling; private tokenManager; constructor(apiCache: APICache, configManager: ConfigManager, tokenManager: TokenManager); /** * Get the CLIENT_ID from environment variable, ConfigManager, or default * Priority: Environment variable > ConfigManager > Default Client ID * * @returns The OAuth Client ID to use for authentication */ private getClientId; /** * Expose resolved client ID for external helpers while preserving internal logic. */ resolveClientId(): Promise; /** * OAuth error codes that require immediate propagation per RFC 6749/8628. * These are terminal errors that cannot be recovered by retrying. */ private static readonly TERMINAL_OAUTH_ERROR_CODES; /** * Error message patterns that indicate terminal OAuth errors. * Used for message-based error detection when error codes aren't available. */ private static readonly TERMINAL_ERROR_PATTERNS; /** * Determines if an OAuth error is terminal and should propagate immediately. * * Per RFC 6749 (OAuth 2.0) and RFC 8628 (Device Authorization Grant): * - Terminal errors (expired_token, access_denied) MUST stop polling immediately * - Transient errors (network failures, slow_down) should be retried * * Error Detection Priority (most to least reliable): * 1. Explicit error code parameter (from GitHub API response) * 2. Error code embedded in Error object properties * 3. Message pattern matching (fallback for compatibility) * * @param error - The error to check * @param errorCode - Optional OAuth error code from API response * @returns true if error is terminal and should propagate, false if retriable * * @see https://datatracker.ietf.org/doc/html/rfc8628#section-3.5 * @see https://docs.github.com/en/developers/apps/authorizing-oauth-apps */ private static isTerminalOAuthError; /** * Execute a network request with retry logic */ private fetchWithRetry; /** * Check current authentication status */ getAuthStatus(): Promise; /** * Initiate the device flow authentication process */ initiateDeviceFlow(): Promise; /** * Poll GitHub for OAuth token using device flow. * * Implements OAuth 2.0 Device Authorization Grant (RFC 8628) with proper error handling. * * ## OAuth 2.0 Compliance (RFC 6749/8628) * * ### Terminal Errors (MUST propagate immediately): * - `expired_token` - Authorization code has expired, user must restart flow * - `access_denied` - User explicitly denied authorization * - `unsupported_grant_type` - Invalid grant type (configuration error) * - `invalid_grant` - Invalid or expired device code * * ### Transient Errors (should be retried): * - `authorization_pending` - User hasn't completed authorization yet * - `slow_down` - Polling too frequently, increase interval * - Network errors (ECONNREFUSED, ETIMEDOUT, etc.) * * ### Error Handling Flow: * 1. GitHub returns error code in response (e.g., `{error: "expired_token"}`) * 2. Check if error is terminal using `isTerminalOAuthError()` * 3. Terminal errors throw immediately, stopping polling * 4. Transient errors are logged and polling continues * 5. After MAX_POLL_ATTEMPTS (15 minutes), timeout error is thrown * * @param deviceCode - Device code from GitHub authorization flow * @param interval - Polling interval in milliseconds (default: 5000ms) * @returns Promise resolving to TokenResponse with access token * @throws {Error} Terminal OAuth errors (expired_token, access_denied, etc.) * @throws {Error} Timeout after MAX_POLL_ATTEMPTS (180 attempts = 15 minutes) * @throws {Error} Network errors that persist beyond retry logic * * @see https://datatracker.ietf.org/doc/html/rfc8628 - OAuth 2.0 Device Authorization Grant * @see https://datatracker.ietf.org/doc/html/rfc6749 - OAuth 2.0 Authorization Framework */ pollForToken(deviceCode: string, interval?: number): Promise; /** * Complete the authentication flow and store the token */ completeAuthentication(tokenResponse: TokenResponse): Promise; /** * Clear stored authentication and revoke token */ clearAuthentication(): Promise; /** * Store token securely using encrypted file storage */ private storeToken; /** * Fetch user information from GitHub */ private fetchUserInfo; /** * Format authentication instructions for users */ formatAuthInstructions(deviceResponse: DeviceCodeResponse): string; /** * Check if user needs to authenticate for a specific action */ needsAuthForAction(action: string): boolean; /** * Wait with abort signal support */ private waitWithAbort; /** * Clean up any active operations (called on server shutdown) */ cleanup(): Promise; /** * Get user-friendly error message based on HTTP status code * Avoids exposing sensitive information while providing helpful guidance */ private getErrorMessageForStatus; } //# sourceMappingURL=GitHubAuthManager.d.ts.map