| 172 | } |
| 173 | |
| 174 | func exchangeToken(config *Config, code string) (*TokenResponse, error) { |
| 175 | data := url.Values{} |
| 176 | data.Set("grant_type", "authorization_code") |
| 177 | data.Set("code", code) |
| 178 | data.Set("client_id", config.ClientID) |
| 179 | data.Set("client_secret", config.ClientSecret) |
| 180 | data.Set("code_verifier", config.CodeVerifier) |
| 181 | data.Set("redirect_uri", config.RedirectURI) |
| 182 | |
| 183 | ctx := context.Background() |
| 184 | req, err := http.NewRequestWithContext(ctx, "POST", config.BaseURL+"/oauth2/tokens", strings.NewReader(data.Encode())) |
| 185 | if err != nil { |
| 186 | return nil, err |
| 187 | } |
| 188 | |
| 189 | req.Header.Set("Content-Type", "application/x-www-form-urlencoded") |
| 190 | |
| 191 | client := &http.Client{Timeout: 10 * time.Second} |
| 192 | resp, err := client.Do(req) |
| 193 | if err != nil { |
| 194 | return nil, err |
| 195 | } |
| 196 | defer resp.Body.Close() |
| 197 | |
| 198 | var tokenResp TokenResponse |
| 199 | if err := json.NewDecoder(resp.Body).Decode(&tokenResp); err != nil { |
| 200 | return nil, xerrors.Errorf("failed to decode response: %w", err) |
| 201 | } |
| 202 | |
| 203 | if tokenResp.Error != "" { |
| 204 | return nil, xerrors.Errorf("token error: %s - %s", tokenResp.Error, tokenResp.ErrorDesc) |
| 205 | } |
| 206 | |
| 207 | return &tokenResp, nil |
| 208 | } |
| 209 | |
| 210 | func showError(w http.ResponseWriter, message string) { |
| 211 | log.Printf("ERROR: %s", message) |