Skip to content

Fix: Slack "Add to Slack" dead-ends on "not signed in" for expired cloud sessions - #660

Open
Nabilhassan12345 wants to merge 1 commit into
andrewyng:mainfrom
Nabilhassan12345:fix/issue-658-slack-cloud-signin
Open

Nabilhassan12345 wants to merge 1 commit into
andrewyng:mainfrom
Nabilhassan12345:fix/issue-658-slack-cloud-signin

Conversation

@Nabilhassan12345

@Nabilhassan12345 Nabilhassan12345 commented Sep 12, 2026

Copy link
Copy Markdown

Fixes #658

Root cause

Two backend checks disagree about sign-in state:

  • cloud.status() (cloud.py:213-219), which powers the GUI's polled /v1/cloud/status and cloud.signed_in, only checks bool(profile.get("access_token")) — presence of a token, not whether it's expired.
  • begin_managed_connect() (cloud.py:345-363), which actually runs on "Add to Slack," calls fresh_access_token(), which checks expiry and tries to refresh — correctly returning {"ok": false, "error": "not signed in", "signed_in": false} when the token is expired with no usable refresh token.

So once a stored session expires, the GUI still shows "signed in" and renders the live "Add to Slack" button. Clicking it hits the real check, which rejects it, and the button's error branch just printed the raw "not signed in" string with no recovery path — exactly what's in the issue screenshot.

Fix (frontend only, surfaces/gui/src)

  • CloudSignIn.tsx: CloudSignInInline now accepts an optional onSignedIn callback, fired once a poll confirms sign-in landed.
  • AddConnectionModal.tsx (SlackOneClick): when connectManaged returns signed_in: false, the pane now switches into the sign-in prompt instead of dead-ending, passing go as onSignedIn so the Slack connect auto-resumes once sign-in completes — no second click needed. A waiting state takes render priority so this doesn't flash "Sign in" again while the Slack OAuth tab is open.
  • api.ts: typed connectManaged's response to include the signed_in field the backend already sends.

Deliberately did not change cloud.status() itself — making it do a live refresh on every 5s poll would add blocking httpx calls into slack_status()/github_status() (called from async def routes without asyncio.to_thread), which is a separate, riskier change outside this bug's scope.

Tests

  • New AddConnectionModal.slack.test.tsx (5 cases): button shown when signed in; stale-signed-in rejection recovers into sign-in instead of dead-ending; sign-in auto-resumes the Slack connect; a genuine non-auth error still shows as an error; fully-signed-out path also auto-continues.
  • New backend tests in test_cloud.py / test_cloud_server.py pin the contract: cloud.status() can say signed_in: True from a stale profile while begin_managed_connect/connect-managed correctly return signed_in: False — the frontend depends on that field, not the error string.

Test plan

  • GUI: npx tsc --noEmit clean; vitest run — 186/186 passed.
  • Backend: pytest tests/test_cloud.py tests/test_cloud_server.py — 40/40 passed. Full suite: 1935 passed, 19 pre-existing failures unrelated to this change (missing optional boto3/slack-bolt deps, sandboxed git worktree) — no production Python code touched.
  • Did not run Playwright e2e (slack-workspaces.spec.ts etc.) — needs a live server + browser install; vitest coverage exercises the same DOM/testids a browser would.
  • Before/after screenshots: force-expire a session (delete refresh_token from the stored cloud:auth profile, or wait out expiry) → Slack → Connect → One click → Add to Slack.

Screenshots

Before — stale-but-"signed in" session: live "Add to Slack" button dead-ends on a bare "not signed in".
before

After — same stale session: recovers into a real sign-in prompt instead of dead-ending.
after

After (auto-resumed) — signing back in automatically resumes the Slack connect, no second click.
after-resumed

🤖 Generated with Claude Code

…ssions

cloud.status() only checked for an access_token's presence, not its
freshness, so the GUI kept showing "signed in" (and the live "Add to
Slack" button) after a session had actually expired. Clicking it hit
begin_managed_connect's real fresh_access_token check, which correctly
rejected it — but the modal just printed the bare error with no way
to recover.

SlackOneClick now treats a signed_in:false response from connectManaged
as a session-expiry signal, switches into the sign-in prompt, and
auto-resumes the Slack connect once sign-in completes.

Fixes andrewyng#658

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
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.

Connector slack does not work

1 participant