package auth import ( "encoding/json" "fmt" "os" "time" ) // claudeCredentialsJSON matches the structure of ~/.claude/.credentials.json. type claudeCredentialsJSON struct { ClaudeAiOauth struct { AccessToken string `json:"accessToken"` RefreshToken string `json:"refreshToken"` ExpiresAt int64 `json:"expiresAt"` SubscriptionType string `json:"subscriptionType"` } `json:"claudeAiOauth"` } // LoadDefaultCredentials reads credentials from ~/.claude/.credentials.json. // Returns nil, nil if the file does not exist. func LoadDefaultCredentials() ([]*Credential, error) { path, err := DefaultCredentialPath() if err != nil { return nil, nil } data, err := os.ReadFile(path) if err != nil { if os.IsNotExist(err) { return nil, nil } return nil, err } var cf claudeCredentialsJSON if err := json.Unmarshal(data, &cf); err != nil { return nil, err } oauth := cf.ClaudeAiOauth if oauth.AccessToken == "" { return nil, fmt.Errorf("no access token in %s", path) } cred := &Credential{ ID: "claude-native", Email: oauth.SubscriptionType, AccessToken: oauth.AccessToken, RefreshToken: oauth.RefreshToken, ExpiresAt: time.UnixMilli(oauth.ExpiresAt), FilePath: path, } return []*Credential{cred}, nil }