package auth import ( "bytes" "encoding/json" "fmt" "io" "kiro-go/config" "net/http" "time" ) // RefreshToken 刷新 access token func RefreshToken(account *config.Account) (string, string, int64, error) { if account.AuthMethod == "social" { return refreshSocialToken(account.RefreshToken) } return refreshOIDCToken(account.RefreshToken, account.ClientID, account.ClientSecret, account.Region) } // refreshOIDCToken IdC/Builder ID token 刷新 func refreshOIDCToken(refreshToken, clientID, clientSecret, region string) (string, string, int64, error) { if clientID == "" || clientSecret == "" { return "", "", 0, fmt.Errorf("OIDC refresh requires clientId and clientSecret") } if region == "" { region = "us-east-1" } url := fmt.Sprintf("https://oidc.%s.amazonaws.com/token", region) payload := map[string]string{ "clientId": clientID, "clientSecret": clientSecret, "refreshToken": refreshToken, "grantType": "refresh_token", } body, _ := json.Marshal(payload) req, _ := http.NewRequest("POST", url, bytes.NewReader(body)) req.Header.Set("Content-Type", "application/json") resp, err := httpClient.Do(req) if err != nil { return "", "", 0, err } defer resp.Body.Close() if resp.StatusCode != 200 { respBody, _ := io.ReadAll(resp.Body) return "", "", 0, fmt.Errorf("refresh failed: %d %s", resp.StatusCode, string(respBody)) } var result struct { AccessToken string `json:"accessToken"` RefreshToken string `json:"refreshToken"` ExpiresIn int `json:"expiresIn"` } if err := json.NewDecoder(resp.Body).Decode(&result); err != nil { return "", "", 0, err } expiresAt := time.Now().Unix() + int64(result.ExpiresIn) return result.AccessToken, result.RefreshToken, expiresAt, nil } // refreshSocialToken Social (GitHub/Google) token 刷新 func refreshSocialToken(refreshToken string) (string, string, int64, error) { url := "https://prod.us-east-1.auth.desktop.kiro.dev/refreshToken" payload := map[string]string{ "refreshToken": refreshToken, } body, _ := json.Marshal(payload) req, _ := http.NewRequest("POST", url, bytes.NewReader(body)) req.Header.Set("Content-Type", "application/json") resp, err := httpClient.Do(req) if err != nil { return "", "", 0, err } defer resp.Body.Close() if resp.StatusCode != 200 { respBody, _ := io.ReadAll(resp.Body) return "", "", 0, fmt.Errorf("refresh failed: %d %s", resp.StatusCode, string(respBody)) } var result struct { AccessToken string `json:"accessToken"` RefreshToken string `json:"refreshToken"` ExpiresIn int `json:"expiresIn"` } if err := json.NewDecoder(resp.Body).Decode(&result); err != nil { return "", "", 0, err } expiresAt := time.Now().Unix() + int64(result.ExpiresIn) return result.AccessToken, result.RefreshToken, expiresAt, nil }