firebase / firebase/firebase-js-sdk

AI (Live API): liveModel().connect() WebSocket does not send the App Check token

Open
#10,018 2 comments 1 reaction 0 assignees View on GitHub
api: firebaseai bug needs-attention
Dominant language
TypeScript
Stars
5.1k
Forks
1k
Avg merge
2d 21h
Merged PRs (30d)
37

Description

### Operating System

Not OS-specific. The defect is in SDK source. Observed in a Chromium browser.

### Environment (if applicable)

Browser-based JS app (also applies to Node >= 22, which is where the Live WebSocket handler runs). Not browser- or runtime-specific; the missing-token code path is the same everywhere.

### Firebase SDK Version

firebase (umbrella) 12.14.0 / @firebase/ai 2.13.0

### Firebase SDK Product(s)

AI

### Project Tooling

Next.js + TypeScript web app. Firebase AI Logic (@firebase/ai) with the Vertex AI backend, App Check enforced via reCAPTCHA Enterprise.

### Detailed Problem Description

**What you were trying to achieve**

Open a Live API session with `getLiveGenerativeModel(...).connect()` on the Vertex AI backend, with App Check enforced on the Firebase AI Logic API (`firebasevertexai.googleapis.com`). App Check is initialized per the official reCAPTCHA Enterprise web guide, with `isTokenAutoRefreshEnabled: true`. HTTPS calls under the same enforcement are confirmed attested and succeed, so the token resolves correctly; only the Live path is affected.

**What actually happened**

The Live WebSocket session never establishes. The server closes the connection during the setup handshake and `connect()` rejects. On the same `AI` instance, with the same App Check setup, the HTTPS methods (`generateContent`, `generateContentStream`, `countTokens`) all work fine. Only the Live (`connect()`) path fails, and it fails the same way in every region tried (`europe-west1`, `europe-west4`, `europe-southwest1`).

**Error messages / unexpected behavior observed**

- The server closes the socket with reason: `Firebase App Check token is invalid.`
- `connect()` then rejects with: `AI: Server connection handshake failed. The server did not respond with a setupComplete message. (AI/response-error)`
- The surprising part: inspecting the actual WebSocket handshake, the App Check token doesn't appear to be sent at all. The `wss://` URL carries only `?key=...` with no App Check token in the query string, and the first `setup` frame contains only the model + generation config. So the server reports "invalid," but from what I can see the token is absent rather than malformed.
- This looks like the same close reason reported for Android in firebase-android-sdk#8060.

**Relevant log snippets / console output**

```
@firebase/vertexai: WebSocket connection closed by server. Reason: 'Firebase App Check token is invalid.'
@firebase/vertexai: WebSocket connection closed by the server with reason: Firebase App Check token is invalid.
FirebaseError: AI: Server connection handshake failed. The server did not respond with a setupComplete message. (AI/response-error)
at lu._connectSession (...)
at async ld.connect (...)
```

Observed handshake URL:

```
wss://firebasevertexai.googleapis.com/ws/google.firebase.vertexai.v1beta.LlmBidiService/BidiGenerateContent/locations/?key=
```

**Possible cause (I might be missing context)**

I poked around the source to understand it. The Live path builds its URL in `WebSocketUrl` (`packages/ai/src/requests/request.ts`) and seems to set only the `key` query param, whereas the HTTPS path's `getHeaders` in the same file attaches `X-Firebase-AppCheck` from `getAppCheckToken()`. I couldn't find a `getAppCheckToken()` call on the Live path, which would line up with the token never being sent. Since a browser/Node `WebSocket` can't set request headers, I'd guess the token has to travel via the URL or the `setup` message instead, but I don't know what the bidi endpoint actually expects.

**Question for maintainers**

Is the intended fix to resolve the App Check token before connecting and pass it on the WebSocket URL or in the `setup` message? Or is the Live path structured this way deliberately for a reason I'm not seeing? Happy to test a patch if that's useful.

### Steps and code to reproduce issue

1. In the Firebase console, enable App Check enforcement for the Firebase AI Logic API (`firebasevertexai.googleapis.com`).
2. Initialize App Check, then call the Live API alongside an HTTPS call. The HTTPS call succeeds and the Live call fails with the same setup:

```ts
import { initializeApp } from 'firebase/app';
import { initializeAppCheck, ReCaptchaEnterpriseProvider } from 'firebase/app-check';
import {
getAI,
getGenerativeModel,
getLiveGenerativeModel,
VertexAIBackend,
ResponseModality
} from 'firebase/ai';

const app = initializeApp({ /* firebaseConfig */ });

initializeAppCheck(app, {
provider: new ReCaptchaEnterpriseProvider(''),
isTokenAutoRefreshEnabled: true
});

// Any location reproduces this; the bug is region-independent.
const ai = getAI(app, { backend: new VertexAIBackend('us-central1') });

// HTTPS path: SUCCEEDS (App Check token sent via the X-Firebase-AppCheck header)
const model = getGenerativeModel(ai, { model: 'gemini-2.5-flash' });
await model.generateContent('ping'); // OK

// Live path: FAILS (no App Check token on the WebSocket handshake)
const liveModel = getLiveGenerativeModel(ai, {
model: 'gemini-live-2.5-flash-native-audio',
generationConfig: { responseModalities: [ResponseModality.AUDIO] }
});
const session = await liveModel.connect();
// connect() rejects; the server closes the socket with
// "Firebase App Check token is invalid."
```

3. Observe that `connect()` rejects while `generateContent()` on the same instance succeeds.
4. To check whether the token is absent rather than malformed: in DevTools, open the Network panel, filter to WS, and inspect the `BidiGenerateContent` connection. The request URL shows only `?key=`, with no App Check token; the first sent frame (`setup`) contains only the model + generation config.
5. As a further check that App Check is the cause: temporarily disable App Check enforcement for the AI Logic API and re-run. The Live path then connects.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.