Skip to content

Commit efae037

Browse files
committed
fix: use correct endpoint for us API
1 parent d028c9e commit efae037

File tree

1 file changed

+40
-2
lines changed

1 file changed

+40
-2
lines changed

sdk/terramate/client.go

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ func WithRegion(region string) ClientOption {
129129
var base string
130130
switch region {
131131
case "us":
132-
base = "https://api.us.terramate.io"
132+
base = "https://us.api.terramate.io"
133133
case "eu":
134134
base = "https://api.terramate.io"
135135
default:
@@ -190,7 +190,9 @@ func (c *Client) newRequest(ctx context.Context, method, path string, body io.Re
190190
return req, nil
191191
}
192192

193-
// do executes an HTTP request and handles the response
193+
// do executes an HTTP request and handles the response.
194+
// If the request fails with 401 Unauthorized and the client uses JWT authentication,
195+
// it attempts to refresh the token and retry the request once.
194196
func (c *Client) do(req *http.Request, v interface{}) (*Response, error) {
195197
const maxBodyBytes = 10 << 20 // 10 MiB
196198
resp, err := c.executeRequestWithRetries(req, 3)
@@ -206,6 +208,25 @@ func (c *Client) do(req *http.Request, v interface{}) (*Response, error) {
206208

207209
response := &Response{HTTPResponse: resp, Body: body}
208210

211+
// Handle 401 Unauthorized - attempt token refresh if using JWT
212+
if resp.StatusCode == http.StatusUnauthorized {
213+
if jwtCred, ok := c.credential.(*JWTCredential); ok {
214+
// Try to refresh the token
215+
if refreshErr := jwtCred.Refresh(req.Context()); refreshErr == nil {
216+
// Token refreshed successfully - retry the request
217+
// Clone the request to avoid reusing the body
218+
retryReq, cloneErr := cloneRequest(req)
219+
if cloneErr == nil {
220+
// Apply the new credentials
221+
if applyErr := c.credential.ApplyCredentials(retryReq); applyErr == nil {
222+
// Recursively call do() for the retry (will not recurse again due to refreshing flag)
223+
return c.do(retryReq, v)
224+
}
225+
}
226+
}
227+
}
228+
}
229+
209230
if resp.StatusCode >= 400 {
210231
return response, parseAPIError(resp, body)
211232
}
@@ -223,6 +244,23 @@ func (c *Client) do(req *http.Request, v interface{}) (*Response, error) {
223244
return response, nil
224245
}
225246

247+
// cloneRequest creates a clone of an HTTP request for retry purposes.
248+
// This is necessary because http.Request.Body can only be read once.
249+
func cloneRequest(req *http.Request) (*http.Request, error) {
250+
clonedReq := req.Clone(req.Context())
251+
252+
// If the request had a body, we need to handle it specially
253+
if req.Body != nil && req.GetBody != nil {
254+
body, err := req.GetBody()
255+
if err != nil {
256+
return nil, fmt.Errorf("failed to get request body: %w", err)
257+
}
258+
clonedReq.Body = body
259+
}
260+
261+
return clonedReq, nil
262+
}
263+
226264
func (c *Client) executeRequestWithRetries(req *http.Request, maxRetries int) (*http.Response, error) {
227265
isIdempotent := req.Method == http.MethodGet || req.Method == http.MethodHead || req.Method == http.MethodOptions
228266
for attempt := 0; attempt <= maxRetries; attempt++ {

0 commit comments

Comments
 (0)