Google Sheets connector setup

Operator·3 minutes to read

This page is the setup half — creating the OAuth app Google Sheets needs in Google's own console and getting its client id and secret into this deployment. Authorising a connection afterwards is the Authenticate control on the plugin sheet, which is what actually sends you to Google.

Google Sheets is its own plugin, beside Google Drive: Drive finds and opens files, Sheets reads and edits cells. A member adds and consents to each on its own.

1. Create the OAuth app in the Google Cloud console

  1. Open the Google Cloud console and create a project (or pick the one your Google Drive connector already uses) — this is your own project, not Botseon's. Under APIs & Services → Library, enable the Google Sheets API. Without it, every call fails with a 403 that names the API as disabled.

  2. Under Authorized redirect URIs, add the redirect URL from docs/connectors/README.md — with the quickstart's default BOTSEON_PUBLIC_URL, that is:

    http://127.0.0.1:3000/api/oauth/google-sheets/callback
    

    One OAuth client can serve Drive, Calendar, Gmail and Sheets: add each connector's redirect URL to the same client.

  3. Create it. Google shows you a client ID and a client secret once — copy both now.

2. Scopes

Read and write are requested separately (F-PLUG-1), and neither is a Drive scope:

  • https://www.googleapis.com/auth/spreadsheets.readonly — see spreadsheets the account can open; no writes.
  • https://www.googleapis.com/auth/spreadsheets — see and edit spreadsheets the account can edit.

Both are sensitive scopes, not restricted ones: an External app needs Google's verification before anyone outside your test users can grant them, but no security assessment. An Internal consent screen (every member in one Workspace organisation) needs neither.

The connector does not use drive.file: that scope reaches only files the app created or opened through a picker, which is not "spreadsheets the account can edit".

3. Enter the app

One command, with the client secret on standard input — there is no flag that takes it and no environment variable that holds it (see docs/connectors/README.md):

printf %s "$CLIENT_SECRET" | botseon oauth-app set \
  --org <organisation id> --slug google-sheets \
  --client-id <the client ID from step 1> \
  --auth-url https://accounts.google.com/o/oauth2/v2/auth \
  --token-url https://oauth2.googleapis.com/token \
  --configured-by <your user id>

It stores the secret encrypted and prints the redirect URL from step 1 back, so you can check the two match. botseon oauth-app show --org <organisation id> --slug google-sheets says whether an app is configured and under which client id; nothing prints the secret back.

Never put either value in a bot's description, a memory, or anywhere else a model reads as ordinary text.

4. What the connector does

  • google-sheets.get_spreadsheet and google-sheets.read_range read; they never ask first.
  • google-sheets.update_cells (values.update) and google-sheets.append_rows (values.append, inserting rows) write, as if typed (valueInputOption=USER_ENTERED). Each waits for the member's approval, and the card names the range.
  • View-only stays view-only. Google answers a write to a spreadsheet the account may only view with 403 PERMISSION_DENIED and changes nothing; the member reads one sentence saying so. The connection stays connected — the grant is fine, the file is simply not theirs to edit.
  • A 403 that is about the deployment instead (the Sheets API disabled in the project, a token missing the scope) is not reported as view-only.

Last verified against build b98ac7c.