Skip to content

fix: resolve infinite redirect loops in auth flows - #64

Open
dylan-klein wants to merge 2 commits into
mainfrom
fix/redirect-loops
Open

fix: resolve infinite redirect loops in auth flows#64
dylan-klein wants to merge 2 commits into
mainfrom
fix/redirect-loops

Conversation

@dylan-klein

Copy link
Copy Markdown
Collaborator

Motivation

Users returning to Pocket CEP the next day (or after a long period of inactivity) were encountering infinite redirect loops in two scenarios:

  1. Service Account Mode: If anonymous session creation failed (e.g. backend was unavailable or timed out), the app would redirect to /?error=session_unavailable, but since the app was in service account mode, the middleware would immediately redirect back to /api/auth/auto-session to try again, causing a loop.
  2. User OAuth Mode: If the Google Access Token expired but the BetterAuth session cookie was still present and valid, the user would navigate to /dashboard, the APIs would return 401s, but because they had a valid BetterAuth session, they couldn't navigate back to / to re-authenticate (the middleware would redirect them back to /dashboard), locking them in.

Main Changes

  • Service Account Mode:
    • Replaced redirects to the landing page with static HTML error pages (renderSaSessionErrorHtml) when anonymous session creation fails in /api/auth/auto-session. This breaks the loop and shows diagnostics.
  • User OAuth Mode:
    • Refactored requireSession in src/lib/session.ts to verify Google Access Token validity if the app is in user_oauth mode. If the token is missing or expired, it automatically deletes the BetterAuth session cookies and returns null (401). This allows the middleware to redirect the user to / for re-authentication.
  • Health Check Route:
    • Updated /api/auth/health to use unauthenticatedResponse() instead of a generic JSON error when session validation fails, ensuring consistent client-side error propagation.
  • Tests:
    • Added unit tests in src/__tests__/unit/session.test.ts to cover token expiration and cookie clearing in user_oauth mode.
    • Added integration tests in src/__tests__/integration/api/auto-session-route.test.ts to assert that failures in auto-session route return 503 HTML instead of redirecting.
    • Updated integration tests in src/__tests__/integration/api/auth-health-route.test.ts to cover both service_account and user_oauth modes.

Design Decisions

  • Decided to clear cookies inside requireSession (server-side) to ensure that any page or API route that requires a session will clean up stale state instantly, avoiding complex client-side redirect handling.
  • Kept the error response on auto-session failure as standard HTML because this endpoint is typically accessed via direct browser navigation during redirect flows, so showing a user-friendly error page with a diagnostic command (npm run doctor) is better than JSON.

- Fixes a redirect loop in service_account mode when anonymous session creation fails by rendering a static HTML error page instead of redirecting to the landing page.
- Fixes a dashboard lock-in bug in user_oauth mode when the Google OAuth token expires but the BetterAuth session remains valid. requireSession now verifies Google token validity and clears cookies early if invalid, allowing navigation back to / for re-authentication.
- Added integration and unit tests for the updated auth routing behaviors.

TAG=agy
CONV=b3471264-2592-4924-b031-267b4bf62326
…nt redirect loops

- Restored client-side redirect to root page on unauthenticated session in user_oauth mode.
- Added explicit authClient.signOut() call before redirecting to ensure local and database-level session cookies are destroyed, preventing concurrent get-session calls from resurrecting the stale cookie.

TAG=agy
CONV=b3471264-2592-4924-b031-267b4bf62326
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant