Calendar OAuth Disconnect RCA — alex@remark.re / Sloane (2026-06-26)

· · 2 min read
View as Markdown Open in ChatGPT Open in Claude

Calendar OAuth Disconnect — Root Cause Analysis (2026-06-26)

Affected: Sloane appointment scheduling (Oppy Inc), alex@remark.re + ag@oppy.pro calendars, and the comms-api ManagedCalendars connected via the same grant.

Summary

On 2026-06-26 a revoke_access (Google Calendar disconnect) fired for oppy User #2 (alex@remark.re). It POSTed to Google’s token-revoke endpoint — actually revoking the grant at Google — then nulled google_calendar_refresh_token and calendar_id locally. Because oppy and comms-api share the same Google OAuth client (GOOGLE_CALENDAR_CLIENT_ID = 883356951770-qkh…), revoking at Google simultaneously killed comms-api’s calendars connected via alex@remark.re — including ag@oppy.pro, Sloane’s primary appointment calendar. One revoke → both apps dark → the appointment schedule stopped working.

The broken record (oppy users, plaintext columns)

User #2 (auth alex@remark.re), updated 2026-06-26 17:03 UTC:

  • google_calendar_refresh_token = nil (wiped)
  • calendar_id = nil (wiped)
  • google_calendar = true (still claims connected)
  • google_sync_token = present (stale leftover)

Mechanism (confirmed in code)

The only oppy path that nulls that column is revoke_access in app/controllers/api/v{2,3}/scheduler/google_calendars_controller.rb:

  • POST https://oauth2.googleapis.com/revoke, then on success: current_user.update(google_calendar_refresh_token: nil, calendar_id: nil)
  • Bug: it does NOT set google_calendar = false, so the account still shows “connected” with no token → silent failure, no reconnect prompt.

Cross-app cascade (oppy ↔ comms-api)

Same OAuth client id across both apps (verified). comms-api’s 16 ManagedCalendars connected via alex@remark.re (incl. ag@oppy.pro/Sloane, spencer.g, kaitlyn.s, ana.p, michael.p@remarkvisions.com, + group calendars) flipped to status=token_expired in the same window because Google revoked the shared grant.

Recovery

The refresh token was revoked at Google, not just deleted locally — so no valid copy exists in any database (comms-api’s is dead too, same grant). Fix = re-authorize: reconnect Google Calendar in oppy (re-consent → fresh refresh token + re-select calendar_id). That restores the appointment schedule and Sloane.

How widespread

  • oppy: of 313 users with google_calendar=true, only 3 have a token; 310 are tokenless — but a long-standing accumulation (scattered across 2023; old disconnects). Only User #2 broke on 06-26 — recent + isolated.
  • comms-api: 178/213 ManagedCalendars connected; 35 token_expired across 8 accounts (grant-specific, not platform-wide).

Engineering follow-ups

  1. revoke_access must set google_calendar=false (and surface “reconnect”) — fixes the silent-broken state behind the 310 stale flags.
  2. Document/guard the oppy↔comms-api shared-OAuth-client coupling: a disconnect in one app revokes calendars in both.
  3. Data cleanup: reconcile the 310 google_calendar=true + no-token users.
  4. Proactive alerting: 7 accounts are fully calendar-dark with no notification.

Verification status

DB facts (nulled token, dates, counts, code path, shared client id) are confirmed. Inferred (strong, consistent): the 06-26 nulling was a revoke_access call that cascaded to comms-api via the shared grant. Unknown: what triggered the revoke (UI click / reconnect-gone-wrong / automated) — recommend a Cloud Logging check for the disconnect-endpoint hit on User #2 on 06-26.