Google API access from the CLI: device flow setup

You want your CLI tool or agent to read your Gmail, update your calendar, or push files to Drive. The obvious paths are wrong in different ways: an API key is too blunt, and a service account JSON key ends up pasted into a config file where anything on the machine can read it. The right path for a personal, user-scoped tool is the RFC 8628 device flow — the “open this URL, enter this code” pattern. Google supports it natively, and it works in headless environments where no browser can open on the same machine.

Why device flow and not a service account

A service account is a machine identity. It is fine for batch jobs on shared resources, but it does not represent you: it cannot see your mail without domain-wide delegation, which is far too big a hammer for a personal script. Device flow gives the tool a scoped token that represents your consent, limited to the scopes you choose, revocable from your Google account at any time.

Step 1: create the client

In the Google Cloud Console, create or select a project, then configure the OAuth consent screen — set the app name, user type, and the scopes you will request. Then create an OAuth client ID of type “TVs and Limited Input devices” — Google’s name for device-flow clients — to get the client_id and client_secret the flow needs. Device flow works with user-type External apps in test mode as long as your own account is an authorized test user.

Step 2: put the client credentials in the config

The device flow client needs its client_id and client_secret somewhere the flow can read them. In a credential broker setup, that is the config file:

[oauth.providers.google]
client_id = "YOUR_CLIENT_ID"
client_secret = "YOUR_CLIENT_SECRET"
scopes = ["https://www.googleapis.com/auth/gmail.readonly"]

Google ships as a built-in provider definition, so the token and device endpoints are already known — you only supply the client credentials and scopes. Keep the scopes as narrow as the task allows; gmail.readonly is a different risk than full gmail.send.

Step 3: log in

Run the login command with a key name. The tool requests a device code, prints the verification URL, and polls until you approve:

$ trustless oauth login google api/gmail
https://oauth2.googleapis.com/device/code   # open this in a browser
{"key":"api/gmail","provider":"google","expires_at":"2026-08-16T12:00:00Z"}

Open the URL in any browser, sign in, enter the code, approve. The broker stores the tokens as a compact single-line JSON entry in the credential store — they never appear in terminal output, shell history, or agent context.

Step 4: use it

From here, consumption is the same as any other credential: trustless run -s api/gmail -- <cmd> injects a fresh access token into the subprocess environment, and the proxy variant injects credentials for HTTP tools. The access token is refreshed automatically at use time, refresh tokens are rotated as single-use, and trustless oauth status tells you whether the entry is valid, expired, or reauth_required. If you revoke access in your Google account, the next refresh fails with invalid_grant and the broker reports reauth_required instead of retrying forever — a re-login with trustless oauth login is the fix.

Every login, refresh, and failure lands in an append-only audit log, which is what you want if this token ever touches production data. The full command set is in the command reference.

The shape of the setup

Three moving parts: a device-flow client in the Google console, client credentials in the config, and a login command that does the approval dance. Everything after that — refresh, rotation, status, audit — is credential-layer plumbing that should not be re-implemented in your script. That plumbing is exactly what a credential broker such as trustless provides, and it is the difference between a Google integration that breaks every hour and one you forget about.

What scopes does your Google CLI tool actually need — and have you checked recently?