summaryrefslogtreecommitdiff
path: root/migrations
diff options
context:
space:
mode:
authorPeter Stone <thepeterstone@gmail.com>2026-09-20 17:44:02 +0000
committerPeter Stone <thepeterstone@gmail.com>2026-09-20 17:44:02 +0000
commit6431cad59bda3da4bafb58fdf91f6a946e42af43 (patch)
tree1c5b6dc9ebbe3e9b34119b3c80812ba28770bb1c /migrations
parent464f9e09c6cde9a2fe66a18500736206ae233d0a (diff)
Surface a dead OAuth grant instead of reporting it as connected
With the cancelled-context bug fixed, the refresh actually reaches Google and the real state of the Google Tasks grant becomes visible: it answers invalid_grant. The stored refresh token has been dead since roughly 2026-08-16. The earlier bug had been masking this — the refresh never got far enough to be rejected. Settings treated the presence of a token row as "Connected", so it reported Google Tasks as connected for a month while every fetch failed. A refresh failure is now persisted (migration 035 adds last_error/last_error_at to oauth_tokens) and cleared on the next success, and settings reports "connected" only when there is no recorded failure. invalid_grant is classified specially, because it is the one failure retrying cannot fix: the message tells the user to reconnect, and notes that a weekly recurrence means the OAuth client is still in Testing publishing status, where Google expires refresh tokens after seven days. Other errors — a network blip, a 5xx — are left as transient rather than pushing the user through consent needlessly. Reconnecting at /settings is still a manual step; nothing here can perform consent on the user's behalf. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018AwnALZL6bD4VBtATDVv3B
Diffstat (limited to 'migrations')
-rw-r--r--migrations/035_oauth_token_errors.sql14
-rw-r--r--migrations/README.md3
2 files changed, 16 insertions, 1 deletions
diff --git a/migrations/035_oauth_token_errors.sql b/migrations/035_oauth_token_errors.sql
new file mode 100644
index 0000000..c0100c0
--- /dev/null
+++ b/migrations/035_oauth_token_errors.sql
@@ -0,0 +1,14 @@
+-- Record why an OAuth token stopped working.
+--
+-- A stored token row was treated as "connected", full stop. When the refresh
+-- token itself goes bad — Google answers invalid_grant, which happens when it
+-- is revoked, superseded, or (for an OAuth client still in Testing publishing
+-- status) simply older than seven days — settings still showed Google Tasks as
+-- connected while every fetch failed in the background.
+--
+-- Persisting the failure lets settings say "reconnect" instead of "connected",
+-- which is the difference between a five-second fix and not knowing anything
+-- is wrong. Cleared on the next successful refresh.
+
+ALTER TABLE oauth_tokens ADD COLUMN last_error TEXT;
+ALTER TABLE oauth_tokens ADD COLUMN last_error_at DATETIME;
diff --git a/migrations/README.md b/migrations/README.md
index 07320af..0382065 100644
--- a/migrations/README.md
+++ b/migrations/README.md
@@ -30,10 +30,11 @@ Migrations are applied automatically on application startup via `store.RunMigrat
| 032 | `032_import_trello_shopping_items.sql` | One-time import of Trello Shopping-board cards (Hardware Store + unlisted) into user items, ahead of removing Trello as a shopping source |
| 033 | `033_ics_feeds.sql` | Subscribed iCalendar (.ics) feeds, merged into calendar_events |
| 034 | `034_shopping_stores_and_sections.sql` | Store/section registry + `user_shopping_items.section` |
+| 035 | `035_oauth_token_errors.sql` | Persist why an OAuth refresh failed, so settings can say "reconnect" |
## Creating New Migrations
-1. Create file: `migrations/NNN_description.sql` (next number is 035)
+1. Create file: `migrations/NNN_description.sql` (next number is 036)
2. Write idempotent SQL (use `IF NOT EXISTS` where possible)
3. Test locally: `go run cmd/dashboard/main.go`
4. Verify: Check `schema_migrations` table for new entry