# Google OAuth

> Connect your personal Google account for Gmail, Calendar, and Drive.

**URL:** https://inference.sh/docs/credentials/google-oauth
**Last updated:** 2026-10-31

---

Connect your personal Google account for Gmail, Calendar, and Drive.

---

## Overview

Google OAuth connects your personal Google account. Sign in and choose which permissions to grant your agents.

**Best for:**
- Personal Gmail inbox
- Your calendar
- Personal Drive files
- Sending emails as yourself
- Search Console and Google Analytics reporting (read-only)

---

## How it works

```
1. Click Connect → Redirect to Google sign-in
2. Review scopes → Choose what to allow
3. Approve → Tokens are encrypted and stored
4. Done → Your agents can access the approved services
```

---

## Connecting

1. Go to **vaults**, open the default vault's **credentials** tab, or open [Google Account](https://app.inference.sh/credentials/google) directly
2. Click **Connect**
3. Sign in with your Google account
4. Review the requested permissions
5. Click **Allow**

You'll be redirected back to the credential detail page with your connection active.

---

## Adding permissions

Already connected but need more access? Add permissions incrementally:

1. Open your connected Google OAuth credential
2. Click **Add Permissions**
3. Select the capabilities you need (e.g., Gmail, Calendar)
4. You'll be redirected to Google to approve the new scopes (Google pre-selects the account you originally connected)
5. Return to inference shell with updated permissions

This uses Google's incremental authorization — your existing permissions are preserved.

---

## Which scopes the platform's client can request

Google connects go through an OAuth client: your workspace's own, if an admin set one up, else the platform's. The platform's Google client is verified by Google for a fixed list of scopes, and inference shell holds it to that list (`allowed_scopes` on the client): a connect or **Add Permissions** that asks for a scope outside it is refused before you are sent to Google, with:

```
scope https://www.googleapis.com/auth/youtube.readonly is not approved for the platform's Google client; connect through your own OAuth app or ask an admin
```

Two ways past it:

- **Your own OAuth client.** A workspace admin registers a Google OAuth client in the [Google Cloud console](https://console.cloud.google.com/apis/credentials) and saves its client id and secret on [Google Account](https://app.inference.sh/credentials/google) (**OAuth app**), or with [`PUT /credentials/google/app`](/docs/api/rest/credentials#set-or-update-app). Logins from that workspace then go through your client, which has no list and may request any scope your Google project allows (Google shows the unverified-app screen for scopes your project is not verified for).
- **Ask an admin.** Platform admins edit the platform client's list in the admin console (the company's platform OAuth app → **allowed scopes**) or as data (`PUT /admin/credentials/google` with `allowed_scopes`); a scope is added once Google has approved it for the platform's project.

An app whose `inf.yml` asks for a scope outside the platform client's list deploys with a warning (`unapproved_platform_scope`), so the author learns at `belt app deploy`; the connect is where it is refused.

---

## Available capabilities

Connect and **Add Permissions** request only the OAuth scope of the capability a tool declares. A login that already holds a broader capability satisfies the narrower one: `google.calendar` covers `google.calendar.events.readonly`, and `google.gmail.modify` covers `google.gmail.labels`.

### Gmail

| Capability | Description | Use case |
|------------|-------------|----------|
| `google.gmail.readonly` | Read emails | Summarize inbox, search messages |
| `google.gmail.send` | Send emails | Send notifications, replies |
| `google.gmail.labels` | See and edit labels | List or rename labels without full mailbox access |
| `google.gmail.modify` | Read, label, archive and organize mail (satisfies `google.gmail.readonly` and `google.gmail.labels`) | Triage inbox, apply labels |
| `google.gmail.compose` | Create and update drafts | Draft replies without sending |

### Calendar

| Capability | Description | Use case |
|------------|-------------|----------|
| `google.calendar.calendarlist.readonly` | See which calendars you subscribe to | Pick a calendar ID before reading events |
| `google.calendar.events.readonly` | View events on your calendars | Read-only agenda or availability |
| `google.calendar.readonly` | View calendar list and events (satisfies `google.calendar.calendarlist.readonly` and `google.calendar.events.readonly`) | Check availability, list meetings |
| `google.calendar.events` | View and edit events, not calendars (satisfies `google.calendar.events.readonly`) | Create meetings, update events |
| `google.calendar.app.created` | Create secondary calendars and manage their events | App-owned calendars |
| `google.calendar.calendars` | Change and delete calendars you can access | Rename or remove a secondary calendar |
| `google.calendar.acls.readonly` | See who calendars are shared with | List a calendar's shares |
| `google.calendar.acls` | Share calendars and change who can see them (satisfies `google.calendar.acls.readonly`) | Share or unshare a calendar |
| `google.calendar` | Read/write calendars, events and sharing (satisfies every calendar capability above) | Create and delete calendars |

### Drive

| Capability | Description | Use case |
|------------|-------------|----------|
| `google.drive.metadata.readonly` | See file and folder names and details | List or search Drive without downloading content |
| `google.drive.readonly` | View file contents (satisfies `google.drive.metadata.readonly`) | Access personal documents |
| `google.drive.file` | Create files and folders, and open files the app created or you picked with it | Uploads, exports, new folders |
| `google.drive` | View and manage all Drive files (satisfies `google.drive.readonly`, `google.drive.metadata.readonly` and `google.drive.file`) | Edit, delete or reorganize files across Drive |

Apps that only create uploads or folders should declare `google.drive.file`, so users are not asked for full Drive access.

### Sheets & Docs

| Capability | Description | Use case |
|------------|-------------|----------|
| `google.sheets.readonly` | Read spreadsheets | Analyze data |
| `google.sheets` | Read/write spreadsheets | Update data |
| `google.docs.readonly` | Read documents | Extract content |
| `google.docs` | Read/write documents | Edit documents |

### Search Console & Analytics

| Capability | Description | Use case |
|------------|-------------|----------|
| `google.searchconsole.readonly` | Read Search Console data for verified sites | Search performance, URL index status, sitemaps |
| `google.analytics.readonly` | Read Google Analytics 4 data | Traffic, acquisition and realtime reports |

---

## Security

| Feature | Benefit |
|---------|---------|
| **Minimal scopes** | Only request what you need |
| **Token encryption** | OAuth tokens are encrypted at rest |
| **Auto-refresh** | We handle token expiration automatically |
| **Revocable** | Disconnect anytime |

### Revoking access

You can revoke access two ways:

1. **From inference shell**: **vaults → credentials → disconnect**
2. **From Google**: [myaccount.google.com/permissions](https://myaccount.google.com/permissions)

---

## Using in apps

Declare OAuth requirements in your app:

```yaml
# inf.yml
credentials:
  - key: google.gmail.send
    description: Send order confirmations

  - key: google.calendar.readonly
    description: Check your availability
    optional: true
```

At runtime, your app receives:

```bash
GOOGLE_OAUTH_ACCESS_TOKEN=ya29...
GOOGLE_OAUTH_TOKEN_EXPIRES_AT=2024-01-15T10:30:00Z
```

### Example: Send an email

```python
import base64
from email.mime.text import MIMEText
from googleapiclient.discovery import build
from google.oauth2.credentials import Credentials

creds = Credentials(token=os.environ["GOOGLE_OAUTH_ACCESS_TOKEN"])
service = build('gmail', 'v1', credentials=creds)

message = MIMEText("Hello from my agent!")
message['to'] = "recipient@example.com"
message['subject'] = "Automated message"

raw = base64.urlsafe_b64encode(message.as_bytes()).decode()
service.users().messages().send(
    userId='me',
    body={'raw': raw}
).execute()
```

### Example: List calendar events

```python
from googleapiclient.discovery import build
from google.oauth2.credentials import Credentials

creds = Credentials(token=os.environ["GOOGLE_OAUTH_ACCESS_TOKEN"])
service = build('calendar', 'v3', credentials=creds)

events = service.events().list(
    calendarId='primary',
    maxResults=10,
    singleEvents=True,
    orderBy='startTime'
).execute()

for event in events.get('items', []):
    print(event['summary'], event['start'])
```

---

## Troubleshooting

### "Token expired" or "Invalid credentials"

- We auto-refresh tokens, but if the refresh token is revoked, you'll need to reconnect
- Open [Google Account](https://app.inference.sh/credentials/google) — the detail page shows an **expired** or **error** banner with the server message and a **Reconnect** button

### "Insufficient permission"

- The requested scope isn't granted
- Use **Add Permissions** to request the missing capability
- Apps will prompt you if they need scopes you haven't granted

### "scope … is not approved for the platform's Google client"

- The connect asked for a scope the platform's verified Google client may not request
- Connect through your workspace's own OAuth client, or ask a platform admin to approve the scope — see [Which scopes the platform's client can request](#which-scopes-the-platforms-client-can-request)

### "Access blocked: This app's request is invalid"

- This usually means the OAuth configuration has an issue
- Contact support if this persists

### Gmail not working but other services are

- Gmail needs the `google.gmail.readonly` or `google.gmail.send` capability, which grants Google's `https://www.googleapis.com/auth/gmail.readonly` or `https://www.googleapis.com/auth/gmail.send` scope
- Check that you've granted the Gmail-specific permissions

---

## OAuth vs Service Account

| Feature | OAuth | Service Account |
|---------|-------|-----------------|
| Setup | Sign in with Google | Get email, share files |
| Access model | Your personal account | Shared file access |
| Best for | Gmail, Calendar, personal files | Shared spreadsheets and docs |
| Token management | Auto-refresh | Auto-generated |

Use **OAuth** for personal services. Use **[Service Account](/docs/credentials/google-service-account)** for shared resources.

---

## Next

→ [Slack](/docs/credentials/slack)

