UNPKG

@sudowealth/schwab-api

Version:

TypeScript client for Charles Schwab API with OAuth support, market data, trading functionality, and complete type safety

92 lines (91 loc) 3.77 kB
import { forceRefreshTokens, } from './token-lifecycle-manager'; /** * Diagnostic function to get detailed information about authentication state * Helps troubleshoot 401 Unauthorized errors by providing token status details * * @param tokenManager The token lifecycle manager to diagnose * @param options Options for diagnostics * @returns Detailed diagnostics information */ export async function getAuthDiagnostics(tokenManager, environment, options = {}) { const { forceRefresh = false, includeTokens = false, includeTokenSegments = true, } = options; // Get the current token status const tokenData = await tokenManager.getTokenData(); // Check if the token manager supports refresh const supportsRefresh = tokenManager.supportsRefresh(); // Extract basic token status const hasAccessToken = !!tokenData?.accessToken; const hasRefreshToken = !!tokenData?.refreshToken; const isExpired = tokenData?.expiresAt ? tokenData.expiresAt <= Date.now() : false; // Calculate time until expiration const expiresInMs = tokenData?.expiresAt ? tokenData.expiresAt - Date.now() : undefined; const expiresInSeconds = expiresInMs !== undefined ? Math.floor(expiresInMs / 1000) : undefined; // Base diagnostic result const result = { authManagerType: tokenManager.constructor.name, supportsRefresh, tokenStatus: { hasAccessToken, hasRefreshToken, isExpired, expiresInMs, expiresInSeconds, }, environment: { apiEnvironment: environment.apiEnvironment, }, }; // Add token segments for debugging (first 8 characters) if (includeTokenSegments && tokenData) { if (tokenData.accessToken) { result.tokenStatus.accessTokenSegment = tokenData.accessToken.substring(0, 8); } if (tokenData.refreshToken) { result.tokenStatus.refreshTokenSegment = tokenData.refreshToken.substring(0, 8); } } // Add client ID segment if available if (environment.clientId) { result.environment.clientIdSegment = environment.clientId.substring(0, 8); } // Include full tokens if requested (only for diagnostic purposes!) if (includeTokens) { result.tokenStatus.tokens = tokenData ?? undefined; } // Force refresh if requested and the token manager supports it if (forceRefresh && supportsRefresh && tokenManager.refreshIfNeeded) { try { // Attempt to force refresh the tokens const refreshedTokens = await forceRefreshTokens(tokenManager); // Update the diagnostic result with refresh information result.tokenStatus.refreshSuccessful = true; result.tokenStatus.newExpiresAt = refreshedTokens.expiresAt; // Update token segments after refresh if (includeTokenSegments) { if (refreshedTokens.accessToken) { result.tokenStatus.accessTokenSegment = refreshedTokens.accessToken.substring(0, 8); } if (refreshedTokens.refreshToken) { result.tokenStatus.refreshTokenSegment = refreshedTokens.refreshToken.substring(0, 8); } } // Update full tokens if requested if (includeTokens) { result.tokenStatus.tokens = refreshedTokens; } } catch (error) { // Record that refresh failed result.tokenStatus.refreshSuccessful = false; // Re-throw the error for proper handling throw error; } } return result; }