↓ Skip to main content
← All research

Gmail API Credentials the Paranoid Way

4 min read Patrik Grobshäuser Archive

Research summary

Setting up Google Cloud OAuth credentials with minimal scopes for an AI email agent — because 'full access' is never the right default.

Email Agent Playbook - This article is part of a series.
Part 1: This Article

Dear Readers,

time to give our agents access to email. But before we wire anything into OpenClaw, we need API credentials — and Google makes it surprisingly easy to give away more access than you intended. This post covers how to set up OAuth credentials with the absolute minimum permissions.

Why Not an App Password?
#

App passwords give full account access. No scope restrictions, no token expiration, no audit trail. For an AI agent that should only read your inbox and draft replies, that’s wildly excessive. OAuth lets us define exactly what the agent can and cannot do at the API level.

Google Cloud Console Setup
#

Head to console.cloud.google.com and create a new project. I called mine openclaw-email — name doesn’t matter, but keeping it separate from other projects means you can nuke it cleanly if needed.

Enable the Gmail API
#

Navigate to APIs & Services > Library, search for “Gmail API”, and enable it. Nothing else. Don’t enable “Google Workspace” or any of the suggested bundles — each enabled API is attack surface you don’t need.

OAuth Consent Screen#

Go to APIs & Services > OAuth consent screen. Choose External user type (unless you have a Workspace org).

Fill in the required fields:

  • App name: Something descriptive like “OpenClaw Email Agent”
  • User support email: Your email
  • Developer contact: Your email again

The important part is the Scopes step. Click “Add or Remove Scopes” and add exactly these two:

https://www.googleapis.com/auth/gmail.readonly
https://www.googleapis.com/auth/gmail.compose

That’s it. gmail.readonly lets the agent read messages and list threads. gmail.compose lets it create drafts. Neither scope allows sending, deleting, or modifying existing messages.

Gotcha: Google will suggest https://mail.google.com/ as a scope — this is the full-access nuclear option. It lets you read, send, delete, and modify anything. Never select this for an agent.

Testing vs Production
#

Leave the app in Testing mode for now. Add your Gmail address as a test user.

Gotcha: Testing mode tokens expire after 7 days. You’ll need to re-authorize weekly until you push to production. For a personal agent this is honestly fine — it forces you to periodically confirm the agent still has the access you intended. If it annoys you later, you can submit for verification, but Google’s review process takes days and requires a privacy policy URL.

Create OAuth Credentials
#

Go to APIs & Services > Credentials and click Create Credentials > OAuth client ID.

  • Application type: Desktop app (not Web application — the token exchange happens locally)
  • Name: openclaw-email-client

Download the JSON file. It’ll be named something like client_secret_123456789.apps.googleusercontent.com.json. Rename it to something sane:

mv ~/Downloads/client_secret_*.json /root/openclaw/gmail-credentials.json

Lock down the permissions:

chmod 600 /root/openclaw/gmail-credentials.json

This file contains your client_id and client_secret. It’s not a token — it can’t access your email on its own — but treat it as sensitive anyway.

First Token Exchange
#

The Gmail MCP server (which we’ll set up in the next post) handles the OAuth flow automatically on first run. But here’s what happens under the hood:

  1. You run the MCP server with the credentials file
  2. It opens a browser for Google’s consent screen
  3. You log in and approve the scopes
  4. Google returns an authorization code
  5. The server exchanges it for an access token + refresh token
  6. Tokens get saved to a local file (typically ~/.gmail-mcp/tokens.json)

The refresh token is what matters long-term. It lets the server get new access tokens without your interaction. Guard it:

chmod 600 ~/.gmail-mcp/tokens.json

Gotcha: If you’re doing this on a headless server (which we are), the browser redirect won’t work directly. Run the initial auth from a machine with a browser, or use SSH port forwarding to handle the localhost callback. The MCP server docs cover the exact flow.

What We’ve Locked Down
#

Let’s take stock of what the agent can and cannot do with these credentials:

ActionAllowed
Read emailsYes
List threadsYes
Search inboxYes
Create draftsYes
Send emailsNo
Delete emailsNo
Modify labelsNo
Access other Google servicesNo

This is the first layer of defense. Even if every other guardrail fails — the SOUL.md gets ignored, the prompt gets injected, the agent goes rogue — it physically cannot send or delete anything. The OAuth scopes are enforced by Google’s servers, not by our code.

We’ll stack more layers on top in later posts. But this one is the foundation, and it’s the only layer that doesn’t depend on the AI behaving correctly.


Next up: Wiring Gmail into OpenClaw

Related