refreshAccessToken obtains a new access token using Client Credentials flow.
()
| 89 | |
| 90 | // refreshAccessToken obtains a new access token using Client Credentials flow. |
| 91 | func (s *Spotify) refreshAccessToken() error { |
| 92 | if s.ClientId.Value == "" || s.ClientSecret.Value == "" { |
| 93 | return errors.New(i18n.T("spotify_not_configured")) |
| 94 | } |
| 95 | |
| 96 | // Prepare the token request |
| 97 | data := url.Values{} |
| 98 | data.Set("grant_type", "client_credentials") |
| 99 | |
| 100 | req, err := http.NewRequest("POST", tokenURL, strings.NewReader(data.Encode())) |
| 101 | if err != nil { |
| 102 | return fmt.Errorf(i18n.T("spotify_failed_create_token_request"), err) |
| 103 | } |
| 104 | |
| 105 | // Set Basic Auth header with Client ID and Secret |
| 106 | auth := base64.StdEncoding.EncodeToString([]byte(s.ClientId.Value + ":" + s.ClientSecret.Value)) |
| 107 | req.Header.Set("Authorization", "Basic "+auth) |
| 108 | req.Header.Set("Content-Type", "application/x-www-form-urlencoded") |
| 109 | |
| 110 | resp, err := s.httpClient.Do(req) |
| 111 | if err != nil { |
| 112 | return fmt.Errorf(i18n.T("spotify_failed_request_access_token"), err) |
| 113 | } |
| 114 | defer resp.Body.Close() |
| 115 | |
| 116 | if resp.StatusCode != http.StatusOK { |
| 117 | body, _ := io.ReadAll(resp.Body) |
| 118 | return fmt.Errorf(i18n.T("spotify_failed_get_access_token"), resp.StatusCode, string(body)) |
| 119 | } |
| 120 | |
| 121 | var tokenResp struct { |
| 122 | AccessToken string `json:"access_token"` |
| 123 | TokenType string `json:"token_type"` |
| 124 | ExpiresIn int `json:"expires_in"` |
| 125 | } |
| 126 | |
| 127 | if err := json.NewDecoder(resp.Body).Decode(&tokenResp); err != nil { |
| 128 | return fmt.Errorf(i18n.T("spotify_failed_decode_token_response"), err) |
| 129 | } |
| 130 | |
| 131 | s.tokenMutex.Lock() |
| 132 | s.accessToken = tokenResp.AccessToken |
| 133 | // Set expiry slightly before actual expiry to avoid edge cases |
| 134 | s.tokenExpiry = time.Now().Add(time.Duration(tokenResp.ExpiresIn-60) * time.Second) |
| 135 | s.tokenMutex.Unlock() |
| 136 | |
| 137 | return nil |
| 138 | } |
| 139 | |
| 140 | // doRequest performs an authenticated request to the Spotify API. |
| 141 | func (s *Spotify) doRequest(method, endpoint string) ([]byte, error) { |
no test coverage detected