TUI Supabase auth flow allows overlap and can hang indefinitely

Open
#35 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
4/5
Estimated time
3-5 days
Newbie friendliness
52/100
Issue type
Bug
Clarity
Mostly clear
Activity status
Quiet
Tech stack
supabase, typescript

Research direction

Start in src/tui/dialog.tsx, reading runAuthFlow, startOAuth, closeDialog, setState, and the authorize() and callback() waits. Trace the dialog lifecycle and existing UI state before adding regression coverage for dismiss-then-retry overlap. Done means one active flow per session, explicit dismiss/retry behavior, and bounded timeout failures for both OAuth calls.

Written by the indexing model from the issue text.

Description

bug priority:p1 status:triaged

Summary

src/tui/dialog.tsx launches the Supabase OAuth flow as fire-and-forget work with no in-flight guard, no cancellation, and no timeout around the authorize() / callback() network calls.

This allows:

  • overlapping auth attempts in a single session
  • background auth work to continue after the dialog is dismissed
  • retries that start a second flow while the first is still running
  • dialogs that can hang forever if the callback path never resolves

Evidence

Fire-and-forget auth start

src/tui/dialog.tsx

  • 178-186: startOAuth = () => runAuthFlow(...)
  • 195: idle state onConfirm: startOAuth

No in-flight state is tracked outside the dialog UI state itself.

Dismiss only closes UI, not the network/auth flow

src/tui/dialog.tsx

  • 139-145: closeDialog() sets lifecycle.closed = true and calls props.onClose()
  • 147-175: setState() stops UI updates after lifecycle.closed

This prevents stale UI changes, but it does not cancel the underlying runAuthFlow() promise or the host OAuth calls it is awaiting.

Retry can overlap a still-running attempt

src/tui/dialog.tsx

  • 224-234: error dialog onConfirm does await startOAuth() again

If a previous attempt is still running in the background, retry starts another flow.

No timeout around host OAuth calls

src/tui/dialog.tsx

  • 65-68: waits on provider.oauth.authorize(...)
  • 97-100: waits on provider.oauth.callback(...)

Neither call has a timeout or abort path.

Reproduction

Overlap case
  1. Run /supabase.
  2. Confirm the dialog and let it reach "Waiting for authorization...".
  3. Dismiss the dialog before completing the browser callback.
  4. Re-open /supabase and start auth again.
  5. Complete one or both browser flows.
Expected

At most one Supabase auth flow should be active per dialog/session/store, and retry should either cancel or await the existing attempt.

Actual

Multiple auth flows can overlap. The first one can continue running after the dialog is gone.

Hang case
  1. Run /supabase.
  2. Start auth.
  3. Make authorize() or callback() stall indefinitely (e.g. broken server path, unreachable host endpoint, unresolved callback).
Expected

User gets a bounded timeout and a recoverable retry path.

Actual

The dialog can remain stuck waiting indefinitely.

Impact

  • Confusing UX with multiple browser tabs or competing flows.
  • Last-finishing auth flow wins, even if it is not the one the user intended.
  • Hanging auth requests have no bounded recovery path.

Suggested Fix

Recommended approach:

  1. Track a single in-flight auth promise for the dialog lifecycle.
  2. Block re-entry while one flow is active, or convert retry into "cancel then restart".
  3. Add timeout wrappers around authorize() and callback().
  4. If possible, thread cancellation/abort through the flow so dismiss actually cancels the work instead of only hiding the UI.

Acceptance Criteria

  • User cannot start a second Supabase auth flow while one is already active.
  • Dismiss/retry semantics are explicit and deterministic.
  • authorize() and callback() fail with a clear timeout instead of hanging forever.
  • Regression coverage exists for dismiss-then-retry overlap.

Notes

This is mostly a reliability/UX issue, but it can indirectly affect correctness because multiple flows can race to update the same local auth store.

Dominant language
TypeScript
Stars
35
Forks
2
PR merge metrics
No merged PRs in 30d

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from supabase-community/opencode-supabase

All issues in supabase-community/opencode-supabase

Similar issues

More TypeScript issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.