From 3343caf5da6f7fd9d73d11ded17a29ff8554d42f Mon Sep 17 00:00:00 2001 From: Denver Coneybeare Date: Tue, 28 Jul 2026 11:12:38 -0400 Subject: [PATCH 1/3] data-connect-api-client-internal.ts: add "X-Client-Platform" and "X-Client-Version" headers Googlers see go/dataconnect:sdk:headers for details --- src/data-connect/data-connect-api-client-internal.ts | 2 ++ .../data-connect/data-connect-api-client-internal.spec.ts | 6 ++++++ 2 files changed, 8 insertions(+) diff --git a/src/data-connect/data-connect-api-client-internal.ts b/src/data-connect/data-connect-api-client-internal.ts index 23c1280efb..64fa2835cd 100644 --- a/src/data-connect/data-connect-api-client-internal.ts +++ b/src/data-connect/data-connect-api-client-internal.ts @@ -74,6 +74,8 @@ function getHeaders(isUsingGen: boolean): { [key: string]: string } { const headerValue = { 'X-Firebase-Client': `fire-admin-node/${utils.getSdkVersion()}`, 'X-Goog-Api-Client': utils.getMetricsHeader(), + 'x-client-platform': 'node', + 'x-client-version': utils.getSdkVersion(), }; if (isUsingGen) { headerValue['X-Goog-Api-Client'] += ' admin-js/gen'; diff --git a/test/unit/data-connect/data-connect-api-client-internal.spec.ts b/test/unit/data-connect/data-connect-api-client-internal.spec.ts index efdfbaa715..01ba007f5b 100644 --- a/test/unit/data-connect/data-connect-api-client-internal.spec.ts +++ b/test/unit/data-connect/data-connect-api-client-internal.spec.ts @@ -53,18 +53,24 @@ describe('DataConnectApiClient', () => { 'Authorization': 'Bearer mock-token', 'X-Firebase-Client': `fire-admin-node/${getSdkVersion()}`, 'X-Goog-Api-Client': getMetricsHeader(), + 'x-client-platform': 'node', + 'x-client-version': getSdkVersion(), }; const EXPECTED_HEADERS_WITH_GEN = { 'Authorization': 'Bearer mock-token', 'X-Firebase-Client': `fire-admin-node/${getSdkVersion()}`, 'X-Goog-Api-Client': getMetricsHeader() + ' admin-js/gen', + 'x-client-platform': 'node', + 'x-client-version': getSdkVersion(), }; const EMULATOR_EXPECTED_HEADERS = { 'Authorization': 'Bearer owner', 'X-Firebase-Client': `fire-admin-node/${getSdkVersion()}`, 'X-Goog-Api-Client': getMetricsHeader(), + 'x-client-platform': 'node', + 'x-client-version': getSdkVersion(), }; const noProjectId = 'Failed to determine project ID. Initialize the SDK with service ' From d2f51f515d9df679ba2f7b452af1fe4ee3f77f87 Mon Sep 17 00:00:00 2001 From: Denver Coneybeare Date: Tue, 28 Jul 2026 15:38:41 -0400 Subject: [PATCH 2/3] Change new headers to use "Pascal-Kebab-Case", for consistency with other headers The new headers `'x-client-platform'` and `'x-client-version'` are defined in lowercase, which is inconsistent with the Pascal-Kebab-Case used for other headers in this object (e.g., `'X-Firebase-Client'`, `'X-Goog-Api-Client'`) and the PR title (`X-Client-Platform` and `X-Client-Version`). For consistency and to match the PR description, these should be capitalized. See https://github.com/firebase/firebase-admin-node/pull/3222#discussion_r3668632749 --- src/data-connect/data-connect-api-client-internal.ts | 4 ++-- .../data-connect-api-client-internal.spec.ts | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/data-connect/data-connect-api-client-internal.ts b/src/data-connect/data-connect-api-client-internal.ts index 64fa2835cd..7168829091 100644 --- a/src/data-connect/data-connect-api-client-internal.ts +++ b/src/data-connect/data-connect-api-client-internal.ts @@ -74,8 +74,8 @@ function getHeaders(isUsingGen: boolean): { [key: string]: string } { const headerValue = { 'X-Firebase-Client': `fire-admin-node/${utils.getSdkVersion()}`, 'X-Goog-Api-Client': utils.getMetricsHeader(), - 'x-client-platform': 'node', - 'x-client-version': utils.getSdkVersion(), + 'X-Client-Platform': 'node', + 'X-Client-Version': utils.getSdkVersion(), }; if (isUsingGen) { headerValue['X-Goog-Api-Client'] += ' admin-js/gen'; diff --git a/test/unit/data-connect/data-connect-api-client-internal.spec.ts b/test/unit/data-connect/data-connect-api-client-internal.spec.ts index 01ba007f5b..d8f5b617b9 100644 --- a/test/unit/data-connect/data-connect-api-client-internal.spec.ts +++ b/test/unit/data-connect/data-connect-api-client-internal.spec.ts @@ -53,24 +53,24 @@ describe('DataConnectApiClient', () => { 'Authorization': 'Bearer mock-token', 'X-Firebase-Client': `fire-admin-node/${getSdkVersion()}`, 'X-Goog-Api-Client': getMetricsHeader(), - 'x-client-platform': 'node', - 'x-client-version': getSdkVersion(), + 'X-Client-Platform': 'node', + 'X-Client-Version': getSdkVersion(), }; const EXPECTED_HEADERS_WITH_GEN = { 'Authorization': 'Bearer mock-token', 'X-Firebase-Client': `fire-admin-node/${getSdkVersion()}`, 'X-Goog-Api-Client': getMetricsHeader() + ' admin-js/gen', - 'x-client-platform': 'node', - 'x-client-version': getSdkVersion(), + 'X-Client-Platform': 'node', + 'X-Client-Version': getSdkVersion(), }; const EMULATOR_EXPECTED_HEADERS = { 'Authorization': 'Bearer owner', 'X-Firebase-Client': `fire-admin-node/${getSdkVersion()}`, 'X-Goog-Api-Client': getMetricsHeader(), - 'x-client-platform': 'node', - 'x-client-version': getSdkVersion(), + 'X-Client-Platform': 'node', + 'X-Client-Version': getSdkVersion(), }; const noProjectId = 'Failed to determine project ID. Initialize the SDK with service ' From 5d71c7fbe8cc8359351ea7ba2ffe7499c77b1b31 Mon Sep 17 00:00:00 2001 From: Denver Coneybeare Date: Thu, 30 Jul 2026 15:20:32 -0400 Subject: [PATCH 3/3] Merge "X-Client-Platform" header into "X-Client-Version" This change was made because the "X-Client-Platform" header causes the CORS OPTIONS preflight request to fail with a 403 "Permission Denied" error due to that header being absent from Google's list of whitelisted CORS headers. In contrast, the "X-Client-Version" header *is* whitelisted and, therefore, successfully passes the CORS preflight. This problem only affects the JS client SDK, but it affected how all platforms, including firebase-admin-node, send their headers. See https://github.com/firebase/firebase-js-sdk/pull/10217 for details. --- src/data-connect/data-connect-api-client-internal.ts | 3 +-- .../data-connect-api-client-internal.spec.ts | 9 +++------ 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/src/data-connect/data-connect-api-client-internal.ts b/src/data-connect/data-connect-api-client-internal.ts index 7168829091..b200eb120e 100644 --- a/src/data-connect/data-connect-api-client-internal.ts +++ b/src/data-connect/data-connect-api-client-internal.ts @@ -74,8 +74,7 @@ function getHeaders(isUsingGen: boolean): { [key: string]: string } { const headerValue = { 'X-Firebase-Client': `fire-admin-node/${utils.getSdkVersion()}`, 'X-Goog-Api-Client': utils.getMetricsHeader(), - 'X-Client-Platform': 'node', - 'X-Client-Version': utils.getSdkVersion(), + 'X-Client-Version': `node/${utils.getSdkVersion()}`, }; if (isUsingGen) { headerValue['X-Goog-Api-Client'] += ' admin-js/gen'; diff --git a/test/unit/data-connect/data-connect-api-client-internal.spec.ts b/test/unit/data-connect/data-connect-api-client-internal.spec.ts index d8f5b617b9..cfc51e5b38 100644 --- a/test/unit/data-connect/data-connect-api-client-internal.spec.ts +++ b/test/unit/data-connect/data-connect-api-client-internal.spec.ts @@ -53,24 +53,21 @@ describe('DataConnectApiClient', () => { 'Authorization': 'Bearer mock-token', 'X-Firebase-Client': `fire-admin-node/${getSdkVersion()}`, 'X-Goog-Api-Client': getMetricsHeader(), - 'X-Client-Platform': 'node', - 'X-Client-Version': getSdkVersion(), + 'X-Client-Version': `node/${getSdkVersion()}`, }; const EXPECTED_HEADERS_WITH_GEN = { 'Authorization': 'Bearer mock-token', 'X-Firebase-Client': `fire-admin-node/${getSdkVersion()}`, 'X-Goog-Api-Client': getMetricsHeader() + ' admin-js/gen', - 'X-Client-Platform': 'node', - 'X-Client-Version': getSdkVersion(), + 'X-Client-Version': `node/${getSdkVersion()}`, }; const EMULATOR_EXPECTED_HEADERS = { 'Authorization': 'Bearer owner', 'X-Firebase-Client': `fire-admin-node/${getSdkVersion()}`, 'X-Goog-Api-Client': getMetricsHeader(), - 'X-Client-Platform': 'node', - 'X-Client-Version': getSdkVersion(), + 'X-Client-Version': `node/${getSdkVersion()}`, }; const noProjectId = 'Failed to determine project ID. Initialize the SDK with service '