Connector ID:
google · Type: oauth_pkce · Catalog entry: src/gaia/connectors/catalog/google.pyWhat you’ll need
Google requires every desktop app — including GAIA running locally — to identify itself with an OAuth client that you create in your own Google Cloud project. This sounds heavy, but for a single-developer machine it takes about five minutes and is free. You will do three things in the Google Cloud Console — enable the APIs you want GAIA to call, register yourself as a test user, and create an OAuth client — then paste two values into the GAIA Agent UI: a Client ID and a Client Secret. After that, GAIA stores them encrypted in your OS keyring and you never need to think about them again.Bringing your own OAuth client is a temporary step. A future GAIA
release (#2104) ships a
verified AMD-managed client so end users skip the Cloud Console entirely
and just click Connect. Until then, the steps below are required for
personal accounts.
Step 1 — Create a Google Cloud project
Use an existing Google Cloud project or follow Google’s guide to creating a project. A name likegaia-personal makes it easy to recognize. Use the same
project for the APIs, consent screen, and OAuth client below.
Step 2 — Enable the APIs you want to use
Enable each API you plan to use:- Gmail API — to read mail (required for Email)
- Google Calendar API — to read/create events
- Google Drive API — to read/manage files
Step 3 — Configure the consent screen (Branding + Audience)
Follow Google’s OAuth consent configuration guide for the project from Step 1. For a personal setup, use an app name such asGAIA Personal, your own support and contact email, and an
External audience with Testing publishing status.
A personal
@gmail.com account has no “Internal” option — Internal
is only available to Google Workspace organizations. External is the
correct (and only) choice for a personal account. An External app starts
in Testing publishing status, which is exactly what you want for
personal use.Add yourself as a test user
While the app is in Testing publishing status (the default), only listed test users can authenticate. Add the Google account you want to connect to GAIA as a test user, following the test-user instructions in Google’s consent configuration guide. You can stay in Testing mode indefinitely if you only use this for yourself — there’s no need to verify the app for personal use.Declare scopes under Data access
Declare the scopes your agents will request on the consent screen, following the scope-selection instructions in Google’s consent configuration guide. This is separate from authorizing the connection or granting scopes inside GAIA. You only need to declare the scopes the agents you actually use will request — the flagshipgaia agent needs only
gmail.readonly; openid / email / profile are requested on every
connection regardless of
agent. email is listed twice, once as the short OIDC name and once as
its userinfo.email URL equivalent — Google treats them as the same
permission, and GAIA asks for whichever the connecting surface uses, so
declare both.
Tiers, sourced from Google’s own tables: Gmail
scopes
and Drive
scopes.
Two corrections worth flagging if you’ve seen older guidance:
gmail.readonly and drive.readonly are Restricted — the same
strictest tier as gmail.modify — not “Sensitive”; read-only buys no
verification relief. drive.file is Non-sensitive, which is why
Google recommends it as the default per-file Drive scope. Google
publishes no tier table for Calendar; calendar.events /
calendar.readonly are listed as Sensitive based on the Console UI’s own
grouping, not an authoritative Google document.
A Testing-status app shows the “Google hasn’t verified this app” warning
for any Sensitive or Restricted scope regardless of whether it’s
declared here — so seeing that warning doesn’t by itself tell you a
scope is missing from Data access.
Unverified: whether Google actually refuses OAuth consent in Testing
mode for a scope that’s requested in the authorization URL but not
declared under Data access has not been checked end-to-end for this
guide — tracked in #2602.
Declaring every scope you’ll use removes the question either way, so do
that regardless of the answer.
Step 4 — Create the OAuth client
Follow Google’s instructions for creating authorization credentials in the project from Step 1. Choose Desktop app as the application type and a recognizable name such asGAIA.
GAIA receives the OAuth callback on a temporary loopback server at
127.0.0.1 with an ephemeral port. A Web application client requires
a registered redirect URI, so use Desktop app instead.
Copy both the Client ID and Client Secret for Step 5. Google’s
OAuth client management guide
explains how to copy or download the credentials.
Step 5 — Paste credentials into GAIA
- Launch the Agent UI:
gaia chat --ui. - Click Settings (gear) → Connections.
- Click the Google tile to expand it.
- Paste the Client ID and Client Secret from Step 4.
- Click Save & Connect.
GAIA_GOOGLE_CLIENT_ID / GAIA_GOOGLE_CLIENT_SECRET,
exactly like gaia connectors configure google.
GAIA will:
- Store the credentials in your OS keyring (macOS Keychain on Mac, gnome-keyring/kwallet on Linux, Credential Locker on Windows).
- Open Google’s consent screen in your default browser.
- Receive the callback on a temporary loopback server.
- Exchange the auth code for a refresh token (also stored in the keyring).
During authorization, a personal test app requesting Gmail or Calendar
scopes can show “Google hasn’t verified this app”. See Google’s
unverified-app guidance
for the consent flow. Check that the app is the OAuth client you
created and that the requested permissions match the scopes you chose.
Prefer the CLI? The whole flow works headless without opening the
Agent UI —
gaia connectors configure google --client-id … --client-secret …
then gaia connectors connect google. See the Email guide’s
setup for the exact commands.gaia connectors list will still say not configured after the configure
step — that is expected, not a failure. For an OAuth connector, “configured”
means a signed-in connection exists in the keyring; saving client credentials
does not create one. It flips only after gaia connectors connect google
completes.Step 6 — Grant scopes to specific agents
Each agent must be granted the specific scopes it needs — a connection alone is not enough. In the Agent UI this happens during connect: the Google tile’s connect panel shows “Grant access to these agents when you connect” with a default-on checkbox per installed agent that declares Google access, and checked agents receive their declared scopes the moment the OAuth flow completes. Uncheck an agent to withhold its grant, and adjust or revoke any grant later under the tile’s Per-agent grants section. On the CLI, lead with--grant-agent — GAIA reads the scopes the agent
already declares in its own code, so there’s no list to type out or keep
in sync:
Flagship gaia agent — the read-only Gmail scope it needs to read and
search your mailbox:
--grant-agent outright for an
agent that declares no Google scopes, rather than silently granting
nothing.
Chat agent — a narrower, read-only Gmail grant: the chat agent
declares no fixed Google requirement, so grant it explicit scopes
instead:
gmail.readonly is a Restricted scope — the same tier as
gmail.modify (see Scopes to declare in your
Console). Read-only narrows what the
agent can do, not which verification tier Google applies.--scopes is a two-command path, and it does not union with the
connection’s default scopes. Authorize with gaia connectors connect google --scopes … first, then grant the same list with gaia connectors grants grant google <agent> --scopes … (the grants grant example
above assumes the scope was already authorized on a prior connect). A
hand-typed list that omits openid can still connect but resolve to
Connected as default instead of your real address — one reason
--grant-agent is the recommended path for any agent that supports it.
The Email guide’s setup has the full two-command
sequence; a missing grant surfaces as AGENT_NOT_GRANTED.src/gaia/connectors/catalog/google.py.
Common issues
Gmail API has not been used in project … or it is disabled (403)
You skipped Step 2, or the enablement hasn’t propagated yet. Enable
the Gmail API
(and Calendar API
if you use calendar) on the selected project, wait 1–2 minutes, and
retry. The OAuth connection itself is fine — only the API call is blocked
(#2116).
AGENT_NOT_GRANTED — an agent can’t use your connection
Connecting Google is not the same as granting a specific agent access to
it (Step 6). Until the per-agent grant lands, the agent surfaces:
gaia connectors grants grant google installed:gaia … command from
Step 6.
redirect_uri_mismatch
You probably picked Web application instead of Desktop app in
Step 4. Delete the OAuth client and create a new one with the right
type — Web application clients require a registered redirect URI,
which GAIA can’t provide because it picks an ephemeral port.
Access blocked: ... has not completed Google verification
Add yourself as a test user (Step 3, “Add yourself as a test user”).
Apps in Testing mode only allow listed test users.
Something went wrong / accounts.google.com/info/unknownerror after you click Allow
Google’s own opaque failure page, shown after you complete the
consent screen — not the “Google hasn’t verified this app” interstitial
from Step 5. GAIA never sees why: the browser lands on Google’s error
page instead of coming back to GAIA’s loopback callback, so the callback
handler never runs and the CLI/UI just times out after two minutes
(OAuth flow ... timed out after 120s. Restart the flow.) — that
message will not name the real cause.
Nothing found while researching this guide ties this error page
authoritatively to one cause for a loopback (Desktop-app) OAuth flow.
Check these, roughly in order of how often they’re reported for this
exact error text:
- Third-party cookies blocked in the browser. The most concrete
reported match for this literal error page — though most reports are
for Google Identity Services JS sign-in widgets embedded in a web
page, not a Desktop-app loopback redirect, so treat this as a lead
rather than a confirmed cause here. Allow third-party cookies for
accounts.google.comand retry. - A stale or mismatched OAuth parameter —
redirect_uri,state, or PKCEcode_challengethat no longer matches what GAIA sent. Restart the flow from GAIA rather than re-using an old consent tab. - Double-clicking Allow, or finishing consent in a second tab/window after the original flow’s state already expired. Restart the flow and complete it in a single tab.
- A transient Google-side incident. Wait a few minutes and retry.
Error 400: invalid_grant after a long while
Refresh tokens expire if your app stays in Testing mode for more than
seven days without use. Reconnect from the Agent UI’s Connections
panel — it will issue a new refresh token.
client_secret is missing
You either skipped pasting the Client Secret in Step 5, or the
connection blob in your keyring predates a GAIA upgrade. Disconnect
and reconnect from the UI to reset.
Revoking access
Two places — both work:- From GAIA: Settings → Connections → Google → Disconnect.
Removes the refresh token from the keyring; the next API call
errors with
NOT_CONNECTED. - From Google: Follow Google’s instructions for removing an app’s access for your OAuth client. Useful if you’ve lost the laptop the keyring lives on.
See also
- Connectors overview
- Email — the flagship agent, which uses
gmail.readonly - Google OAuth client runbook — the AMD-internal client + rotation procedure (maintainers)
- Manage OAuth Clients — Google Cloud Console Help
- Get started with the Google Auth Platform — Google Cloud Console Help
- Connectors security model