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
If you already have a project you use for hobby projects, skip ahead. Otherwise:- Go to the Google Cloud Console.
- Click the project dropdown at the top → New project.
- Name it something like
gaia-personaland click Create. - Make sure the new project is selected in the dropdown before continuing — every step below applies to the selected project.
Step 2 — Enable the APIs you want to use
Enable each API you plan to use:- Gmail API — to read/send mail (required for the Email Triage agent)
- Google Calendar API — to read/create events
- Google Drive API — to read/manage files
Step 3 — Configure the consent screen (Branding + Audience)
Google requires you to fill in a consent-screen form before it will issue OAuth credentials, even for personal-use apps. In the new console this is the Google Auth Platform.- Go to Google Auth Platform (old path: APIs & Services → OAuth consent screen). On a fresh project you’ll see a Get started button — click it to enter the short setup wizard.
- Branding — fill in the required fields:
- App name:
GAIA Personal(or whatever) - User support email: your email
- Developer contact email: your email
- App name:
- Audience — pick External.
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 your own Google account:- On the Google Auth Platform → Audience tab, scroll to Test users → Add users.
- Enter your Google email and Save.
Declare scopes under Data access
Every scope GAIA can request must also be declared on the consent screen — a separate step from anything you type into agaia command,
and easy to miss because nothing in the flow above mentions it.
You only need to declare the scopes the agents you actually use will
request — the Email Triage agent needs gmail.modify,
gmail.send, calendar.events, and calendar.readonly; openid /
email / profile are requested on every connection regardless of
agent.
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
This is the credential GAIA uses.- Go to Google Auth Platform → Clients (old path: APIs & Services → Credentials) → Create client.
- Application type: Desktop app.
- Name:
GAIA(or whatever you want). - Click Create. A dialog shows the Client ID and Client Secret. Copy both — you’ll paste them into GAIA in a moment. You can also download the JSON.
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 you’ll hit a “Google hasn’t verified this app”
interstitial. This is expected for a personal test app — click
Advanced → Continue (or Go to GAIA Personal (unsafe)) to
proceed. The warning only appears because your app is unverified, not
because anything is wrong.
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 Triage guide’s CLI
tab for the exact commands.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:
Email Triage agent — the full mailbox + calendar scope set it needs
to read, organize, draft/send, and manage events:
--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 Triage guide’s CLI tab has the full
two-command sequence; a missing grant either way 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:email … 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: myaccount.google.com/permissions → find your OAuth client → Remove access. Useful if you’ve lost the laptop the keyring lives on.
See also
- Connectors overview
- Email Triage agent — the agent that uses these Gmail scopes
- 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