Upgrade Google Sheets OAuth scope to spreadsheets (write) #436
Labels
No labels
domain:backend
domain:devops
domain:frontend
status:approved
status:in-progress
status:needs-fix
status:qa
type:bug
type:devops
type:feature
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
ldraney/basketball-api#436
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Type
Feature
Lineage
Standalone — spawned from the westside-sheet-sync project scaffold on 2026-04-10. Prerequisite for every other ticket in the sheet-sync series; the sync cannot append rows to the sheet with a read-only token.
Repo
forgejo_admin/basketball-apiUser Story
As ops
I want the westsidebasktball@gmail.com OAuth token to include the
spreadsheetswrite scopeSo that the sheet_sync service can append new paid jersey orders to Marcus's Google Sheet without a second token or service account
Ties to
story:sheet-sync— see story-westside-jersey-sheet-sync.Context
Tonight (2026-04-10) we did a one-shot OAuth consent to get the Google Sheets
spreadsheets.readonlyscope on the westsidebasktball@gmail.com account. The resulting refresh token lives at~/secrets/google-oauth/sheets-westsidebasketball.json. That token can read the "Westside" jersey order sheet but cannot write to it. The sheet_sync service (separate ticket) needs write access to call the Sheets APIvalues:appendendpoint.Scopes are locked at consent time — you cannot "upgrade" an existing token to cover a new scope. The only path is a fresh consent flow with the new scope requested. One-time browser interaction, then the new refresh token is good indefinitely.
The existing consent script
~/westside-sheets/auth_sheets_remote.pyis already parameterized for this — change one constant fromspreadsheets.readonlytospreadsheetsand re-run. The new token lands in a new file so the readonly token continues to work for anything that uses it.File Targets
Files to create:
~/westside-sheets/auth_sheets_remote_write.py— copy ofauth_sheets_remote.pywithSCOPE = "https://www.googleapis.com/auth/spreadsheets"andTOKEN_PATH = Path.home() / "secrets/google-oauth/sheets-westsidebasketball-write.json". Alternatively, parameterize the existing script to take a--scopeand--outflag and drop the duplicate file.Files NOT to touch:
auth_sheets_remote.py— preserve the readonly consent flow exactly as-is for anything that uses it.~/secrets/google-oauth/sheets-westsidebasketball.json— keep the readonly token intact.Acceptance Criteria
westsidebasktball@gmail.com.https://www.googleapis.com/auth/spreadsheetsis written to~/secrets/google-oauth/sheets-westsidebasketball-write.jsonwith mode 0600.https://oauth2.googleapis.com/tokeninfo?access_token=<access>with the new token, then the response includes thespreadsheetsscope (notspreadsheets.readonly).values:appendendpoint with a test range and body using the new token, then the response is HTTP 200 with the appended row's range.Test Expectations
tokeninfoendpoint confirmsscope: https://www.googleapis.com/auth/spreadsheets.python3 ~/westside-sheets/auth_sheets_remote_write.py startthenfinish <redirect_url>Constraints
refresh_token(useaccess_type=offlineandprompt=consentlike the existing flow).Checklist
~/westside-sheets/— this lives outside a git repo)Related
westside-sheet-sync— project this affectsstory-westside-jersey-sheet-sync— user story