# Gcloud

> Use this skill when working with Google Cloud CLI (gcloud), Google Cloud APIs, Google Search Console API, Google Workspace APIs, OAuth authentication with specific scopes, enabling GCP APIs, managing GCP projects, or making authenticated REST API calls to Google services.

- Skill: `wrsmith108/gcloud` (Agent Skill, multi-file: 4 files)
- Install (CLI): `npx skillmds@latest add wrsmith108/gcloud`
- Raw SKILL.md: https://api.skillmd.com/api/skills/wrsmith108/gcloud/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: DevOps & Infra
- Author: wrsmith108 (https://skillmd.com/u/wrsmith108)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/wrsmith108/gcloud

---


# gcloud Skill

Patterns for Google Cloud CLI operations, OAuth authentication with custom scopes, and making authenticated calls to Google APIs including Search Console, Webmaster Tools, and other Workspace APIs.

## Behavioral Classification

**Type**: Guided Decision

**Directive**: ASK, THEN EXECUTE

Identify which Google API and operation is needed, then execute the appropriate auth + API call pattern.

---

## Critical: gcloud Auth Scope Limitations

`gcloud auth login` and `gcloud auth application-default login` grant a **fixed set of Cloud-platform scopes**. They do **not** include Google Workspace API scopes such as:

| API | Required Scope | Included in gcloud login? |
|-----|---------------|--------------------------|
| Search Console / Webmasters | `https://www.googleapis.com/auth/webmasters` | ❌ No |
| Gmail | `https://www.googleapis.com/auth/gmail.readonly` | ❌ No |
| Drive | `https://www.googleapis.com/auth/drive` | ❌ No |
| Calendar | `https://www.googleapis.com/auth/calendar` | ❌ No |
| Sheets | `https://www.googleapis.com/auth/spreadsheets` | ❌ No |
| Cloud platform APIs | `https://www.googleapis.com/auth/cloud-platform` | ✅ Yes |

**Workaround**: `gcloud auth application-default login --scopes=<scope>,https://www.googleapis.com/auth/cloud-platform` appears to work but gcloud's cloud-platform requirement overrides custom scopes at token generation time. Use the Python localhost OAuth flow instead.

---

## Pattern 1: Custom-Scope OAuth Token (Workspace APIs)

When a Workspace API scope is needed, run the bundled helper script:

```bash
# Generates a scoped token and saves it to /tmp/google_token.json
python3 ~/.claude/skills/gcloud/scripts/oauth_token.py \
  --scope "https://www.googleapis.com/auth/webmasters"
```

The script:
1. Starts a local HTTP server on port 9876
2. Opens a browser OAuth consent screen
3. Captures the auth code automatically via redirect
4. Exchanges it for an access token
5. Saves token JSON to `/tmp/google_token.json`

Then read the token in subsequent API calls:

```python
import json
with open('/tmp/google_token.json') as f:
    TOKEN = json.load(f)['access_token']
```

---

## Pattern 2: Enable a GCP API

Before calling any Google API, ensure it is enabled for the active project:

```bash
# Check active project
gcloud config get-value project

# Enable an API
gcloud services enable searchconsole.googleapis.com
gcloud services enable drive.googleapis.com
gcloud services enable sheets.googleapis.com

# List all enabled APIs
gcloud services list --enabled
```

---

## Pattern 3: Authenticated REST Calls

All Google API calls require `Authorization: Bearer <token>` and — for APIs accessed via application credentials — `X-Goog-User-Project: <project-id>`.

```python
import json, urllib.request

with open('/tmp/google_token.json') as f:
    TOKEN = json.load(f)['access_token']

PROJECT = subprocess.check_output(['gcloud', 'config', 'get-value', 'project']).decode().strip()

def gapi(url, method='GET', data=None):
    req = urllib.request.Request(url, data=data, method=method)
    req.add_header('Authorization', f'Bearer {TOKEN}')
    req.add_header('X-Goog-User-Project', PROJECT)
    if data is not None:
        req.add_header('Content-Length', str(len(data)))
    try:
        with urllib.request.urlopen(req) as resp:
            return resp.status, json.load(resp)
    except urllib.error.HTTPError as e:
        return e.code, json.loads(e.read())
```

---

## Pattern 4: Search Console API

Requires scope: `https://www.googleapis.com/auth/webmasters`

```python
import urllib.parse

SITE_URL = urllib.parse.quote('https://www.example.com/', safe='')

# Submit a sitemap
status, body = gapi(
    f'https://www.googleapis.com/webmasters/v3/sites/{SITE_URL}/sitemaps/'
    + urllib.parse.quote('https://www.example.com/sitemap-index.xml', safe=''),
    method='PUT', data=b''
)
# 204 = success

# Get sitemap status
status, body = gapi(
    f'https://www.googleapis.com/webmasters/v3/sites/{SITE_URL}/sitemaps/'
    + urllib.parse.quote('https://www.example.com/sitemap-index.xml', safe='')
)
# body contains: path, isPending, lastSubmitted, warnings, errors

# List all sitemaps
status, body = gapi(
    f'https://www.googleapis.com/webmasters/v3/sites/{SITE_URL}/sitemaps'
)

# List verified sites
status, body = gapi('https://www.googleapis.com/webmasters/v3/sites')
```

> **Note**: "Request Indexing" (URL Inspection → Request Indexing in GSC dashboard) has **no API equivalent**. It must be done manually in the GSC web interface. The Google Indexing API only supports `JobPosting` and `BroadcastEvent` schema types, not general pages.

---

## Pattern 5: Token Scope Verification

Always verify a token has the required scope before making API calls:

```python
import urllib.request, json

def check_scopes(token):
    req = urllib.request.Request(
        f'https://www.googleapis.com/oauth2/v1/tokeninfo?access_token={token}'
    )
    with urllib.request.urlopen(req) as resp:
        info = json.load(resp)
    return info.get('scope', '').split()

scopes = check_scopes(TOKEN)
print('Granted scopes:', scopes)
```

---

## Common Errors

| Error | Cause | Fix |
|-------|-------|-----|
| `insufficientPermissions` (403) | Token lacks required scope | Use `oauth_token.py` script for custom scopes |
| `Your application is authenticating by using local ADC... requires a quota project` | Missing `X-Goog-User-Project` header | Add `X-Goog-User-Project: <project-id>` to every request |
| `API has not been used in project ... before or it is disabled` | API not enabled | `gcloud services enable <api>.googleapis.com` |
| `invalid_scope` | Scope URL was truncated (line-wrap in terminal) | Copy scope as a single unbroken string |
| `EOFError: EOF when reading a line` | gcloud interactive prompt blocked by non-TTY context | Run `gcloud auth` commands directly in your terminal, not through an automated tool |

---

## Quick Reference: Auth Decision Tree

```
Need to call a Google API?
│
├─ Cloud platform API (GCP, BigQuery, GCS, etc.)
│   └─ Use: gcloud auth print-access-token
│
└─ Google Workspace API (Search Console, Drive, Gmail, Sheets, etc.)
    └─ Use: python3 ~/.claude/skills/gcloud/scripts/oauth_token.py --scope "<scope>"
```

---

## Environment Variables

| Variable | Required | Description |
|----------|----------|-------------|
| `GOOGLE_CLOUD_PROJECT` | No | Override active GCP project (else uses `gcloud config get-value project`) |
| `GOOGLE_TOKEN_FILE` | No | Override token file path (default: `/tmp/google_token.json`) |

---

## References

- [Scope Patterns](references/scope-patterns.md) — full list of Google API scopes and their use cases
- [oauth_token.py](scripts/oauth_token.py) — standalone OAuth helper script

