Skip to content

auth: Google reauth callback leaves returning user temporary #1827

@tyler-dane

Description

@tyler-dane

Bug report

A returning Google Calendar-connected user can complete Google OAuth reauthorization, land back in Compass, and still remain on a temporary account. The app then shows the generic toast Google authorization could not be completed. Please try again. even though the Google consent flow was successful.

This blocks returning users whose Compass session is no longer active from getting back to their existing account through the Google Calendar reauth path.

Where it happened

Route/screen: /auth/google/callback returning to the calendar day view.

Account state from reporter: returning user successfully reauthenticates with Google Calendar auth, but after redirect the sidebar still shows Temporary account / Sign up.

Screenshot evidence: the app is on the day view, the planner sidebar says Temporary account, and the bottom-left toast says Google authorization could not be completed. Please try again.

Workflow

  1. Start from a returning user/browser that previously used Google Calendar auth but is currently shown as a temporary account.
  2. Initiate Google Calendar reauthentication/authorization.
  3. Complete Google OAuth successfully and return to Compass through /auth/google/callback.
  4. The app navigates back to the calendar but shows the generic Google authorization failure toast and still treats the user as temporary.

Expected outcome

A successful returning-user Google authorization should restore the user's existing Compass session/account, refresh user metadata, and leave the sidebar showing the authenticated user rather than Temporary account.

If the Compass session is expired and Google OAuth cannot restore it through the current flow, the app should route the user through the proper sign-in/session recovery path instead of attempting the authenticated Google connect endpoint and showing a generic authorization failure.

Screenshot

[screenshot]

Diagnosis

Reproduction status: not locally reproduced because this requires a live Google OAuth/backend setup and the reporter's returning-user/session-expired account state. Diagnosis confidence is medium-high from code inspection and the supplied screenshot.

Strongest evidence:

  • packages/web/src/views/GoogleAuthCallback/GoogleAuthCallback.tsx calls completeGoogleAuthorization(), shows showErrorToast(result.message) on failure, then navigates to the saved return path.
  • packages/web/src/auth/google/authorization/complete-google-authorization.ts chooses behavior only from the saved sessionStorage intent. For connectCalendar, it calls authApi.connectGoogle(payload), then refreshes metadata. Any unparsed error becomes the generic Google authorization could not be completed. Please try again. message.
  • packages/web/src/common/apis/auth.api.ts maps connectGoogle() to POST /api/auth/google/connect.
  • packages/backend/src/auth/auth.routes.config.ts protects /api/auth/google/connect with verifySession(). If the returning user's Compass session is absent/expired, this endpoint cannot complete even after Google OAuth succeeds.
  • packages/web/src/components/PlannerSidebar/PlannerAccountSummary/PlannerAccountSummary.tsx renders Temporary account when useUser() has no email, matching the screenshot after the callback failure.
  • Acceptance docs say returning/authenticated connect-later flows should keep the existing Compass session and use POST /api/auth/google/connect; they do not cover a session-expired returning user who is already temporary at callback time.

Related issue: #1479 describes the broader expired-session/Google-connected-user recovery problem. This report captures the concrete OAuth callback failure and temporary-account symptom.

Likely fix

Start with the Google authorization intent/callback boundary:

  • In useStartGoogleAuthorization / completeGoogleAuthorization, distinguish connectCalendar from returning-user sign-in/reauth when there is no active Compass session.
  • Before calling POST /api/auth/google/connect, verify the Compass session is active or make the backend return a typed/session-expired error that the callback can handle intentionally.
  • For expired/no-session returning users, complete Google auth through the sign-in/session restoration path (loginOrSignup / SuperTokens flow) or redirect to the auth modal with a specific message, rather than treating it as an in-session Google Calendar connect.
  • Preserve the existing in-session connect behavior for password-authenticated users connecting Google for the first time, including email mismatch and already-connected safeguards in connectGoogleToCurrentUser().

Likely affected files/modules:

  • packages/web/src/auth/google/authorization/complete-google-authorization.ts
  • packages/web/src/auth/google/authorization/useStartGoogleAuthorization.ts
  • packages/web/src/views/GoogleAuthCallback/GoogleAuthCallback.tsx
  • packages/web/src/common/apis/auth.api.ts
  • packages/backend/src/auth/auth.routes.config.ts
  • packages/backend/src/auth/controllers/auth.controller.ts
  • packages/backend/src/auth/services/google/google.auth.service.ts

Verification

Shortest practical verification:

  1. Use a Google-connected returning user whose Compass session is expired or otherwise absent, so the sidebar shows Temporary account.
  2. Start Google Calendar reauth and complete OAuth successfully.
  3. Confirm the callback does not show the generic Google authorization failure toast.
  4. Confirm the sidebar shows the restored authenticated user and Google metadata/import state refreshes.
  5. Also verify the existing authenticated connect-later path still calls POST /api/auth/google/connect and keeps pre-existing Compass data.

Focused automated coverage to add:

  • Web unit test for completeGoogleAuthorization() covering a connectCalendar intent when authApi.connectGoogle() returns/throws an unauthorized session error, asserting the user sees a specific recovery behavior instead of the generic Google authorization failure.
  • Existing connectCalendar success test should continue asserting metadata refresh and event refetch.
  • Backend/controller test can assert /api/auth/google/connect remains session-protected and returns a typed response/error that the callback can distinguish.

Metadata

Metadata

Assignees

No one assigned

    Labels

    backendWork related to improving the Compass APIwebFrontend/web related issue

    Type

    No fields configured for Bug.

    Projects

    Status
    Backlog

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions