@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
JavaScript
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;
}