diff --git a/CHANGELOG.md b/CHANGELOG.md index 2c704ae..e154aa9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed +- Send the auth header as `api-access-token` so proxies that drop underscore headers (e.g. Caddy 2.6.4+) no longer cause `401`s. ([#41](https://github.com/chatwoot/cli/issues/41)) + ## [0.6.1] - 2026-06-03 ### Fixed diff --git a/internal/cmd/api_test.go b/internal/cmd/api_test.go index 9208a9e..703bf47 100644 --- a/internal/cmd/api_test.go +++ b/internal/cmd/api_test.go @@ -20,8 +20,8 @@ func TestApiCmdCallsAccountScopedEndpoint(t *testing.T) { http.Error(w, "unexpected path: "+r.URL.Path, http.StatusNotFound) return } - if r.Header.Get("api_access_token") != "test-token" { - t.Errorf("api_access_token = %q, want test-token", r.Header.Get("api_access_token")) + if r.Header.Get("api-access-token") != "test-token" { + t.Errorf("api-access-token = %q, want test-token", r.Header.Get("api-access-token")) } w.Header().Set("Content-Type", "application/json") _, _ = w.Write([]byte(`{"id":123,"status":"open"}`)) diff --git a/internal/sdk/CLAUDE.md b/internal/sdk/CLAUDE.md index de9c993..8f0e9ab 100644 --- a/internal/sdk/CLAUDE.md +++ b/internal/sdk/CLAUDE.md @@ -122,7 +122,7 @@ Authenticated user profile. ## Authentication - Token resolved by callers from `CHATWOOT_API_KEY` or the OS keyring -- Injected as `api_access_token` header on all requests +- Injected as `api-access-token` header on all requests (hyphens, not underscores: proxies like Caddy 2.6.4+ and nginx drop underscore headers by default; Rack maps both to `HTTP_API_ACCESS_TOKEN`) - Token must have `conversation:read`, `message:read`, `message:write` scopes ## File Organization diff --git a/internal/sdk/client.go b/internal/sdk/client.go index 2999ded..450acee 100644 --- a/internal/sdk/client.go +++ b/internal/sdk/client.go @@ -69,7 +69,7 @@ func (c *Client) request(method, path string, body io.Reader) (*http.Request, er return nil, err } - req.Header.Set("api_access_token", c.APIKey) + req.Header.Set("api-access-token", c.APIKey) req.Header.Set("Content-Type", "application/json") return req, nil @@ -81,7 +81,7 @@ func (c *Client) rawRequest(method, path string, body io.Reader) (*http.Request, return nil, err } - req.Header.Set("api_access_token", c.APIKey) + req.Header.Set("api-access-token", c.APIKey) req.Header.Set("Content-Type", "application/json") return req, nil diff --git a/internal/sdk/contract_test.go b/internal/sdk/contract_test.go index 59ccc29..8635b28 100644 --- a/internal/sdk/contract_test.go +++ b/internal/sdk/contract_test.go @@ -398,8 +398,8 @@ func newContractClient(t *testing.T, handler func(*testing.T, *http.Request, *op func validateContractRequest(t *testing.T, r *http.Request) *openapi3filter.RequestValidationInput { t.Helper() - if got := r.Header.Get("api_access_token"); got != contractAPIKey { - t.Fatalf("api_access_token header = %q, want %q", got, contractAPIKey) + if got := r.Header.Get("api-access-token"); got != contractAPIKey { + t.Fatalf("api-access-token header = %q, want %q", got, contractAPIKey) } route, pathParams, err := getContractRouter(t).FindRoute(r) diff --git a/internal/sdk/help_center_test.go b/internal/sdk/help_center_test.go index 41cf766..2bde55c 100644 --- a/internal/sdk/help_center_test.go +++ b/internal/sdk/help_center_test.go @@ -12,8 +12,8 @@ func TestHelpCenterListPortalsCallsAccountEndpoint(t *testing.T) { http.Error(w, "unexpected path: "+r.URL.Path, http.StatusNotFound) return } - if r.Header.Get("api_access_token") != "test-token" { - t.Errorf("api_access_token = %q, want test-token", r.Header.Get("api_access_token")) + if r.Header.Get("api-access-token") != "test-token" { + t.Errorf("api-access-token = %q, want test-token", r.Header.Get("api-access-token")) } w.Header().Set("Content-Type", "application/json")