Hi all,
I am building a React Native application that uses the Gemini Multimodal Live API via WebSockets. To avoid exposing my API Key on the client side, I am generating Ephemeral Tokens (via client.auth_tokens.create) in a Python FastAPI backend and passing them to the mobile app.
The Problem: I cannot establish a WebSocket connection using the generated ephemeral token. No matter how I pass the token, the connection closes immediately with one of these errors:
-
Error: Method doesn't allow unregistered callers (callers without established identity). -
Error: API key not valid. Please pass a valid API key.
Backend Code (Python): I am using the google-genai library to create the token.
Python
from google import genai
# ... setup ...
client = genai.Client(api_key=settings.GEMINI_API_KEY, http_options={'api_version': 'v1alpha'})
# Generating the token
token_obj = client.auth_tokens.create(
config = {
'uses': 10, # Increased usage limit to avoid race conditions
'live_connect_constraints': {
'model': 'models/gemini-2.0-flash-exp',
'config': {
'generation_config': { 'response_modalities': ['AUDIO'] }
}
},
'http_options': {'api_version': 'v1alpha'},
}
)
# This returns a string like: "authTokens/ab123456..."
return { "token": token_obj.name }
Frontend Code (React Native): I am trying to connect to the WebSocket.
JavaScript
// The token received is: "authTokens/ab123456..."
// ATTEMPT 1: Passing as 'key' query param (URL Encoded)
const encodedToken = encodeURIComponent(data.token);
const wsUrl = `wss://generativelanguage.googleapis.com/ws/google.ai.generativelanguage.v1alpha.GenerativeService.BidiGenerateContent?key=${encodedToken}`;
const ws = new WebSocket(wsUrl);
// RESULT: "API key not valid" or "Unregistered callers"
// ATTEMPT 2: Passing as Bearer Token in Headers
const wsUrl = `wss://generativelanguage.googleapis.com/ws/google.ai.generativelanguage.v1alpha.GenerativeService.BidiGenerateContent`;
const ws = new WebSocket(wsUrl, [], {
headers: {
'Authorization': `Bearer ${data.token}`
}
});
// RESULT: "Method doesn't allow unregistered callers"
// ATTEMPT 3: Passing as 'x-goog-api-key' Header
const ws = new WebSocket(wsUrl, [], {
headers: {
'x-goog-api-key': data.token
}
});
// RESULT: Connection closed immediately.
What I have verified:
-
If I hardcode my real
API_KEY(AIza…) in the URL (?key=AIza...), the WebSocket connects perfectly. The issue is strictly related to the Ephemeral Token format/usage. -
The token generated by Python has the format
auth_tokens/xxxx. -
I have tried encoding the
/as%2Fin the URL. -
I have tried using
gemini-2.0-flash-expandgemini-2.5-flash-native-audio-preview.
Question: What is the correct way to pass an authToken (Ephemeral Token) to the BidiGenerateContent WebSocket endpoint? Does the WebSocket endpoint support these tokens, or is it restricted to API Keys and OAuth?
Thank you so much for your help!
Best,