Summary
The new "Google Cloud" AI account connection (gemini_api_oauth) in v2.8 connects successfully, but every model call at runtime fails with HTTP 401 UNAUTHENTICATED. The root cause appears to be that Google's OpenAI-compatibility endpoint (generativelanguage.googleapis.com/v1beta/openai) only accepts API keys as the bearer credential, while the proxy forwards the user's OAuth access token.
Environment
- Agent Zero v2.8 (2026-08-01), official Docker image
agent0ai/agent-zero:latest
- Windows 11 host, Docker Desktop, default port mapping
- User-provided Google Cloud OAuth client (Web application type), Generative Language API enabled, consent screen in Testing mode
Steps to reproduce
- Create a Google Cloud OAuth client per the connect card's requirements; enable the Generative Language API.
- Connect the "Google Cloud" account in Settings — browser PKCE flow completes,
usr/plugins/_oauth/gemini_api/auth.json is written with valid access + refresh tokens.
- Select a model via the connected provider (e.g.
gemini-3.5-flash) and send any chat message.
- Every call through the proxy (
/oauth/gemini-api/v1) fails with 401 from Google.
Evidence that the token itself is valid
Using the exact access token from auth.json:
| Endpoint |
Result |
GET v1beta/models (native) |
200 OK — models listed |
POST v1beta/models/gemini-3.5-flash:generateContent (native) |
200 OK — text generated |
POST v1beta/openai/chat/completions (OpenAI-compat) |
401 UNAUTHENTICATED — "Request is missing required authentication credential. Expected OAuth 2 access token, login cookie or other valid authentication credential." |
The 401 on the compat endpoint persists in all variants tried: with and without x-goog-user-project set to the project ID, and set to the project number. Same result for gemini-3.5-flash and gemini-3.1-flash-lite. So the OAuth token is fully capable against the native API, but the OpenAI-compat layer rejects it outright — consistent with Google's docs, which only document Authorization: Bearer <GEMINI_API_KEY> for that endpoint.
Where this lives in the code
plugins/_oauth/helpers/providers/gemini_api.py — GEMINI_OPENAI_API_BASE = ".../v1beta/openai"; _gemini_headers() sends Authorization: Bearer <oauth access token> (plus x-goog-user-project when a quota project is configured).
plugins/_oauth/conf/model_providers.yaml — gemini_api_oauth routes runtime traffic through the local proxy (litellm_provider: openai, api_base: http://127.0.0.1/oauth/gemini-api/v1), which forwards to the compat endpoint with those headers.
Suggested direction
Route runtime calls for this provider through the native v1beta API (which demonstrably accepts these OAuth tokens) instead of the OpenAI-compat layer — e.g. LiteLLM's gemini provider with the OAuth token supplied via auth headers — or, if that's not feasible, surface a clear error/note in the connect card that the account cannot currently be used for model calls.
Related observation (can file separately if preferred)
On free-tier Gemini API keys, chat calls fail with 429 TotalCachedContentStorageTokensPerModelFreeTier limit exceeded (limit=0) because Agent Zero always requests explicit prompt caching for Gemini (agent.py passes explicit_caching=True; no settings toggle exists). Free tier allows zero cached-content storage, so every call dies. A per-provider/per-preset toggle for explicit caching — or an automatic fallback to uncached calls when cache creation 429s — would make the free tier usable out of the box.
Setup, testing, and diagnosis performed with AI assistance (Claude); all findings verified against the running v2.8 container.
Summary
The new "Google Cloud" AI account connection (
gemini_api_oauth) in v2.8 connects successfully, but every model call at runtime fails with HTTP 401 UNAUTHENTICATED. The root cause appears to be that Google's OpenAI-compatibility endpoint (generativelanguage.googleapis.com/v1beta/openai) only accepts API keys as the bearer credential, while the proxy forwards the user's OAuth access token.Environment
agent0ai/agent-zero:latestSteps to reproduce
usr/plugins/_oauth/gemini_api/auth.jsonis written with valid access + refresh tokens.gemini-3.5-flash) and send any chat message./oauth/gemini-api/v1) fails with 401 from Google.Evidence that the token itself is valid
Using the exact access token from
auth.json:GET v1beta/models(native)POST v1beta/models/gemini-3.5-flash:generateContent(native)POST v1beta/openai/chat/completions(OpenAI-compat)The 401 on the compat endpoint persists in all variants tried: with and without
x-goog-user-projectset to the project ID, and set to the project number. Same result forgemini-3.5-flashandgemini-3.1-flash-lite. So the OAuth token is fully capable against the native API, but the OpenAI-compat layer rejects it outright — consistent with Google's docs, which only documentAuthorization: Bearer <GEMINI_API_KEY>for that endpoint.Where this lives in the code
plugins/_oauth/helpers/providers/gemini_api.py—GEMINI_OPENAI_API_BASE = ".../v1beta/openai";_gemini_headers()sendsAuthorization: Bearer <oauth access token>(plusx-goog-user-projectwhen a quota project is configured).plugins/_oauth/conf/model_providers.yaml—gemini_api_oauthroutes runtime traffic through the local proxy (litellm_provider: openai,api_base: http://127.0.0.1/oauth/gemini-api/v1), which forwards to the compat endpoint with those headers.Suggested direction
Route runtime calls for this provider through the native
v1betaAPI (which demonstrably accepts these OAuth tokens) instead of the OpenAI-compat layer — e.g. LiteLLM'sgeminiprovider with the OAuth token supplied via auth headers — or, if that's not feasible, surface a clear error/note in the connect card that the account cannot currently be used for model calls.Related observation (can file separately if preferred)
On free-tier Gemini API keys, chat calls fail with
429 TotalCachedContentStorageTokensPerModelFreeTier limit exceeded (limit=0)because Agent Zero always requests explicit prompt caching for Gemini (agent.pypassesexplicit_caching=True; no settings toggle exists). Free tier allows zero cached-content storage, so every call dies. A per-provider/per-preset toggle for explicit caching — or an automatic fallback to uncached calls when cache creation 429s — would make the free tier usable out of the box.Setup, testing, and diagnosis performed with AI assistance (Claude); all findings verified against the running v2.8 container.