https://open.dingtalk.com/document/orgapp/obtain-the-access_token-of-an-internal-app
(ctx context.Context, c *http.Client, id, secret string)
| 250 | |
| 251 | // https://open.dingtalk.com/document/orgapp/obtain-the-access_token-of-an-internal-app |
| 252 | func getToken(ctx context.Context, c *http.Client, id, secret string) (*tokenValue, error) { |
| 253 | payload := fmt.Sprintf(`{"appKey":"%s","appSecret":"%s"}`, id, secret) |
| 254 | const url = "https://api.dingtalk.com/v1.0/oauth2/accessToken" |
| 255 | body := strings.NewReader(payload) |
| 256 | req, err := http.NewRequestWithContext(ctx, http.MethodPost, url, body) |
| 257 | if err != nil { |
| 258 | return nil, errors.Wrapf(err, "construct POST %s", url) |
| 259 | } |
| 260 | req.Header.Set("Content-Type", "application/json") |
| 261 | resp, err := c.Do(req) |
| 262 | if err != nil { |
| 263 | return nil, errors.Wrapf(err, "POST %s", url) |
| 264 | } |
| 265 | |
| 266 | b, err := io.ReadAll(resp.Body) |
| 267 | if err != nil { |
| 268 | return nil, errors.Wrapf(err, "read body of POST %s", url) |
| 269 | } |
| 270 | defer resp.Body.Close() |
| 271 | |
| 272 | if resp.StatusCode != http.StatusOK { |
| 273 | return nil, errors.Errorf("non-200 POST status code %d with body %q", resp.StatusCode, b) |
| 274 | } |
| 275 | |
| 276 | var response struct { |
| 277 | Token string `json:"accessToken"` |
| 278 | Expire int `json:"expireIn"` |
| 279 | } |
| 280 | if err := json.Unmarshal(b, &response); err != nil { |
| 281 | return nil, errors.Wrapf(err, "unmarshal body from POST %s", url) |
| 282 | } |
| 283 | |
| 284 | return &tokenValue{ |
| 285 | token: response.Token, |
| 286 | expireAt: time.Now().Add(time.Second * time.Duration(response.Expire)), |
| 287 | }, nil |
| 288 | } |