From c02f5e80077f4f90270bfd0e931bfd41f3fcfaac Mon Sep 17 00:00:00 2001 From: sohey Date: Thu, 27 Aug 2026 15:43:44 +0200 Subject: [PATCH] fix(sync): auth to LLM Gateway via x-api-key instead of Bearer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The base-std docs sync started failing with a 403 Cloudflare "Attention Required" block page on the first gateway call (both the Haiku manifest pre-pass and the per-page Sonnet calls), while base/base's Claude Code Review workflow — same BaseRunnerGroup runners, same llm-gateway.coinbase-corp.com, same LLM_GATEWAY_API_KEY — kept working. The difference was the auth header. The SDK's `authToken` option sends `Authorization: Bearer `, whereas base/base reaches the gateway via claude-code-action's `anthropic_api_key`, which sends the standard Anthropic `x-api-key` header. The gateway's Cloudflare edge treats x-api-key traffic as trusted and bot-challenges requests without it, producing the 403 before the request reaches the app (hence the instant failure, not a 401/JSON). Switch the client from `authToken` to `apiKey` so it sends `x-api-key`, matching the working workflow. Comment-only doc fixes to match. Co-Authored-By: Claude --- scripts/sync-from-base-std/llm/client.mjs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/scripts/sync-from-base-std/llm/client.mjs b/scripts/sync-from-base-std/llm/client.mjs index 5ead3fd73..31b8cd2a2 100644 --- a/scripts/sync-from-base-std/llm/client.mjs +++ b/scripts/sync-from-base-std/llm/client.mjs @@ -4,8 +4,8 @@ * Uses @anthropic-ai/sdk only as the message-protocol client for Coinbase's * internal LLM Gateway (https://llm-gateway.coinbase-corp.com). The base URL * is explicitly set to the Gateway and authentication uses the internal - * LLM_GATEWAY_API_KEY as a Bearer token. This client does not make direct - * requests to an external model-provider API. + * LLM_GATEWAY_API_KEY sent as the standard Anthropic `x-api-key` header. This + * client does not make direct requests to an external model-provider API. * * Owns three responsibilities: * @@ -74,8 +74,13 @@ function getClient() { ); } _client = new GatewayMessagesClient({ - // The internal Gateway requires Bearer-token authentication. - authToken: gatewayToken, + // The Gateway authenticates on the standard Anthropic `x-api-key` header. + // Using `apiKey` (not `authToken`) makes the SDK send `x-api-key` rather + // than `Authorization: Bearer`; requests without `x-api-key` are treated + // as untrusted by the Gateway's Cloudflare edge and get a 403 bot + // challenge before reaching the app. This matches base/base's working + // Claude Code workflow, which passes the same key via `anthropic_api_key`. + apiKey: gatewayToken, baseURL: GATEWAY_BASE_URL, // Retries cover 408 / 429 / 5xx / network errors with exponential backoff. maxRetries: 4,