fix(auth): check .credentials.json for Linux profile authentication (#1492)
* fix(auth): check .credentials.json for Linux profile authentication Fixes ACS-388: Custom Claude profiles never mark as authenticated on Linux. The isProfileAuthenticated function was not checking .credentials.json, which is where the Claude CLI stores OAuth tokens on Linux. This caused custom profiles to always show "Needs Auth" even after successful OAuth. Changes: - Add .credentials.json to possibleAuthFiles array in profile-utils.ts - Includes comment explaining Linux-specific usage Refs: ACS-388 * refactor(auth): validate .credentials.json content structure Implement Gemini Code Assist suggestion to make .credentials.json authentication check more robust by validating the JSON content structure instead of just checking file length. The previous check only verified content.length > 10, which could pass for invalid token files. The new validation properly parses and validates the OAuth data structure: - claudeAiOauth with accessToken, refreshToken, email, or emailAddress - oauthAccount.emailAddress (alternative structure) - Generic token fields (legacy formats) This matches the robust validation pattern used for .claude.json and aligns with the existing checkProfileAuthentication function in claude-code-handlers.ts. Refs: #1492 --------- Co-authored-by: StillKnotKnown <stillknotknown@users.noreply.github.com> Co-authored-by: Andy <119136210+AndyMik90@users.noreply.github.com>
This commit is contained in:
@@ -88,6 +88,39 @@ export function isProfileAuthenticated(profile: ClaudeProfile): boolean {
|
||||
}
|
||||
}
|
||||
|
||||
// Check for .credentials.json with OAuth tokens (Linux CLI storage)
|
||||
// On Linux, the Claude CLI stores OAuth tokens in this file
|
||||
const credentialsJsonPath = join(configDir, '.credentials.json');
|
||||
if (existsSync(credentialsJsonPath)) {
|
||||
try {
|
||||
const content = readFileSync(credentialsJsonPath, 'utf-8');
|
||||
const data = JSON.parse(content);
|
||||
// Validate OAuth data structure
|
||||
// Check for claudeAiOauth (primary Linux structure)
|
||||
if (data && typeof data === 'object' && data.claudeAiOauth) {
|
||||
// Validate that claudeAiOauth contains actual auth data
|
||||
const hasValidAuth = data.claudeAiOauth.accessToken ||
|
||||
data.claudeAiOauth.refreshToken ||
|
||||
data.claudeAiOauth.email ||
|
||||
data.claudeAiOauth.emailAddress;
|
||||
if (hasValidAuth) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// Check for oauthAccount (alternative structure)
|
||||
if (data && typeof data === 'object' && data.oauthAccount?.emailAddress) {
|
||||
return true;
|
||||
}
|
||||
// Check for generic token fields (legacy formats)
|
||||
if (data && typeof data === 'object' && (data.accessToken || data.refreshToken || data.token)) {
|
||||
return true;
|
||||
}
|
||||
} catch (error) {
|
||||
// Log parse errors for debugging, but fall through to legacy checks
|
||||
console.warn(`[profile-utils] Failed to read or parse ${credentialsJsonPath}:`, error);
|
||||
}
|
||||
}
|
||||
|
||||
// Legacy: Claude stores auth in .claude/credentials or similar files
|
||||
// Check for common auth indicators
|
||||
const possibleAuthFiles = [
|
||||
|
||||
Reference in New Issue
Block a user