getToken fetches an OAuth2 token using client credentials flow.
(ctx context.Context, c *http.Client, tenantID, clientID, clientSecret, scope string)
| 87 | |
| 88 | // getToken fetches an OAuth2 token using client credentials flow. |
| 89 | func getToken(ctx context.Context, c *http.Client, tenantID, clientID, clientSecret, scope string) (*tokenValue, error) { |
| 90 | tokenURL := fmt.Sprintf("https://login.microsoftonline.com/%s/oauth2/v2.0/token", tenantID) |
| 91 | |
| 92 | data := url.Values{} |
| 93 | data.Set("client_id", clientID) |
| 94 | data.Set("client_secret", clientSecret) |
| 95 | data.Set("scope", scope) |
| 96 | data.Set("grant_type", "client_credentials") |
| 97 | |
| 98 | req, err := http.NewRequestWithContext(ctx, http.MethodPost, tokenURL, strings.NewReader(data.Encode())) |
| 99 | if err != nil { |
| 100 | return nil, errors.Wrapf(err, "failed to construct token request") |
| 101 | } |
| 102 | req.Header.Set("Content-Type", "application/x-www-form-urlencoded") |
| 103 | |
| 104 | resp, err := c.Do(req) |
| 105 | if err != nil { |
| 106 | return nil, errors.Wrapf(err, "failed to request token") |
| 107 | } |
| 108 | defer resp.Body.Close() |
| 109 | |
| 110 | b, err := io.ReadAll(resp.Body) |
| 111 | if err != nil { |
| 112 | return nil, errors.Wrapf(err, "failed to read token response") |
| 113 | } |
| 114 | |
| 115 | if resp.StatusCode != http.StatusOK { |
| 116 | return nil, errors.Errorf("token request failed (status %d): %s", resp.StatusCode, string(b)) |
| 117 | } |
| 118 | |
| 119 | var tokenResp tokenResponse |
| 120 | if err := json.Unmarshal(b, &tokenResp); err != nil { |
| 121 | return nil, errors.Wrapf(err, "failed to unmarshal token response") |
| 122 | } |
| 123 | |
| 124 | return &tokenValue{ |
| 125 | token: tokenResp.AccessToken, |
| 126 | expireAt: time.Now().Add(time.Second * time.Duration(tokenResp.ExpiresIn)), |
| 127 | }, nil |
| 128 | } |
| 129 | |
| 130 | func getTokenCached(ctx context.Context, c *http.Client, tenantID, clientID, clientSecret, scope string) (string, error) { |
| 131 | tokenCacheLock.Lock() |