Skip to content

fix(vscode): show actionable message when cloud sign-in has no linked…(#1299)#1464

Open
kairavb wants to merge 1 commit into
rocketride-org:developfrom
kairavb:fix/RR-1299-cloud-signin-no-account-message
Open

fix(vscode): show actionable message when cloud sign-in has no linked…(#1299)#1464
kairavb wants to merge 1 commit into
rocketride-org:developfrom
kairavb:fix/RR-1299-cloud-signin-no-account-message

Conversation

@kairavb

@kairavb kairavb commented Jul 5, 2026

Copy link
Copy Markdown

… account

Summary

  • VS Code cloud sign-in showed a cryptic "no token received" error for brand-new users with no RocketRide account yet, with no indication of what went wrong or what to do.
  • Replaced it with an actionable message ("No RocketRide account found for this login. Create an account on RocketRide Cloud, then sign in again.") plus a "Create Account" button that opens the RocketRide Cloud signup page.
  • Genuine auth failures are unaffected — they still throw and are handled separately in the existing catch block.

Type

  • Fix

Testing

  • Tests added or updated
  • Tested locally
  • ./builder test passes

Checklist

  • Commit messages follow conventional commits
  • No secrets or credentials included
  • Wiki updated (if applicable)
  • Breaking changes documented (if applicable)

Linked Issue

Fixes #1299

Summary by CodeRabbit

  • New Features
    • Enhanced sign-in recovery: users now see clearer guidance when sign-in finishes without an account token.
    • When needed, the app can open the appropriate cloud page (including account creation) directly from the sign-in flow.
  • Bug Fixes
    • Improved OAuth callback handling by distinguishing between a pending-access/waitlisted state and “no active API key/API key inactive,” with more helpful user messaging.

@github-actions github-actions Bot added the module:vscode VS Code extension label Jul 5, 2026
@coderabbitai

coderabbitai Bot commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 445719a7-6940-4c2c-a2c5-0ff25a9c6b43

📥 Commits

Reviewing files that changed from the base of the PR and between a062260 and 9275910.

📒 Files selected for processing (1)
  • apps/vscode/src/auth/CloudAuthProvider.ts

📝 Walkthrough

Walkthrough

The VS Code extension now resolves environment-specific RocketRide Cloud URLs and distinguishes successful, waitlisted, and inactive-account outcomes during OAuth token exchange. Users without an active API key are prompted to open RocketRide Cloud, while waitlisted users receive an informational message.

Changes

Cloud sign-in result handling

Layer / File(s) Summary
Cloud URL resolution and OAuth callback handling
apps/vscode/src/auth/CloudAuthProvider.ts
Adds ConnectResult typing and resolveCloudAppUrl, moves configuration validation before client creation, and handles successful, waitlisted, and no-token results with appropriate messages and browser navigation.

Estimated code review effort: 2 (Simple) | ~10 minutes

Suggested reviewers: jmaionchi, rod-christensen, stepmikhaylov

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is concise and matches the cloud sign-in messaging change, even if slightly truncated.
Linked Issues check ✅ Passed The PR addresses #1299 by replacing the empty-token failure with actionable guidance and keeps genuine auth failures in the catch path.
Out of Scope Changes check ✅ Passed The changes stay within the sign-in/onboarding flow and URL resolution needed for the linked issue.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

apps/vscode/src/auth/CloudAuthProvider.ts

Oops! Something went wrong! :(

ESLint: 9.39.4

TypeError: expand is not a function
at Minimatch.braceExpand (/node_modules/.pnpm/minimatch@3.1.5/node_modules/minimatch/minimatch.js:271:10)
at Minimatch.make (/node_modules/.pnpm/minimatch@3.1.5/node_modules/minimatch/minimatch.js:180:33)
at new Minimatch (/node_modules/.pnpm/minimatch@3.1.5/node_modules/minimatch/minimatch.js:156:8)
at doMatch (/node_modules/.pnpm/@eslint+config-array@0.21.2/node_modules/@eslint/config-array/dist/cjs/index.cjs:422:13)
at match (/node_modules/.pnpm/@eslint+config-array@0.21.2/node_modules/@eslint/config-array/dist/cjs/index.cjs:756:11)
at /node_modules/.pnpm/@eslint+config-array@0.21.2/node_modules/@eslint/config-array/dist/cjs/index.cjs:772:10
at Array.some ()
at pathMatches (/node_modules/.pnpm/@eslint+config-array@0.21.2/node_modules/@eslint/config-array/dist/cjs/index.cjs:767:44)
at /node_modules/.pnpm/@eslint+config-array@0.21.2/node_modules/@eslint/config-array/dist/cjs/index.cjs:1368:8
at FlatConfigArray.forEach ()


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@kairavb kairavb changed the title fix(vscode): show actionable message when cloud sign-in has no linked… fix(vscode): show actionable message when cloud sign-in has no linked…(#1299) Jul 6, 2026
@Rod-Christensen

Copy link
Copy Markdown
Collaborator

Thanks for picking this up — the old "no token received" toast was genuinely useless, and the direction here (actionable message + button) is exactly right. Before we merge, though, I traced the server side of this flow and the premise behind the new message doesn't hold up.

A resolved connect() with an empty userToken doesn't mean "no account exists." The cloud PKCE path auto-provisions brand-new users on first sign-in — upsert_user followed by provision_new_user bootstraps their org, team, and API key before the auth result is built. So there is no success path where the login completes but no RocketRide account exists. The two states that actually produce a successful auth with an empty userToken are:

  1. Waitlisted user — the email isn't matched in the user_grants whitelist, so the account is created with is_enabled = false and the server intentionally returns waitlisted: true with an empty userToken so clients can render a waitlist screen. This is almost certainly what VS Code extension: cloud sign-in shows "no token received" for users without a RocketRide account (should guide them to sign up) #1299 users are hitting: their account was created, it's just pending access.
  2. Revoked keys — an enabled user whose rr_* API keys are all inactive falls back to an empty userToken in get_authentication_result.

In both cases the new message sends the user the wrong way. A waitlisted user who clicks "Create Account", signs up, and signs in again lands right back on the same error — a frustrating loop with no exit. A revoked-keys user is told to create an account they already have.

Suggested change: branch on result.waitlisted — it's already exposed on ConnectResult (see packages/client-typescript/src/client/types/client.ts), and this code already reads the result via (result as any). That would mirror how shell-ui handles the same state (Shell.tsx renders a dedicated waitlist phase). Something like:

  • waitlisted === true → "Your RocketRide account is pending access approval. You'll be able to sign in once access is granted."
  • otherwise (empty token, not waitlisted) → a message about no active API key for the account.

A few smaller things while you're in there:

  • CLOUD_SIGNUP_URL hardcodes the production URL while the token exchange targets process.env.ROCKETRIDE_URI — against a staging/dev cloud, the button would open production. The extension already has rocketride.deployment.hostUrl; deriving the link from that (or from ROCKETRIDE_URI) keeps environments consistent.
  • If openExternal throws, the catch block reports "RocketRide Cloud sign-in failed" even though sign-in didn't fail at that point. Worth moving the open outside the try, or catching it separately.
  • The inline comment ("no linked RocketRide account yet") should be updated to describe the waitlist/revoked-key semantics above so the next reader isn't misled.

Happy to walk through the server-side trace if useful. The structure of the change is solid — it's just the interpretation of the empty-token branch that needs adjusting.

@kairavb
kairavb force-pushed the fix/RR-1299-cloud-signin-no-account-message branch from a062260 to 9275910 Compare July 14, 2026 08:00
@github-actions

Copy link
Copy Markdown
Contributor
🤖 Internal: Discord sync marker

Auto-managed by the Discord notification workflow. Stores the linked Discord message ID and forum thread ID. Do not edit or delete.

@kairavb

kairavb commented Jul 14, 2026

Copy link
Copy Markdown
Author

Thanks for the detailed review and the server-side trace—it clarified where my assumption was wrong. I've updated the implementation to branch on result.waitlisted, show a pending-access message for waitlisted users, distinguish the inactive API key case, derive the Cloud URL from the deployment configuration instead of hardcoding it, and separate openExternal() failures from the sign-in flow. I'd appreciate another look when you have a chance.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/vscode/src/auth/CloudAuthProvider.ts`:
- Around line 43-56: Update resolveCloudAppUrl so its parse-failure path no
longer returns the hardcoded production URL; instead fail safely by returning
the configured cloudApiUrl unchanged or using the existing flow to suppress the
Cloud button. Preserve the current URL transformation for valid configured
deployments.
- Around line 214-225: Separate the authentication and cleanup flows in the
method containing the temporary RocketRideClient: keep connect() failures
handled by the existing sign-in error path, but run tempClient.disconnect() in
independent cleanup handling after a successful connection. Ensure disconnect
errors do not return early or prevent the subsequent storeToken and
storeUserName operations from processing the successful ConnectResult.
- Around line 137-174: Update handleGoogleOAuth so error and missing-token
responses notify the matching pending Google OAuth waiter before returning,
rather than deleting it without resolution. Add or reuse an explicit failure
callback/error response alongside the success callback established by
setPendingGoogleOAuth, while preserving nodeId matching and sole-waiter fallback
behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 445719a7-6940-4c2c-a2c5-0ff25a9c6b43

📥 Commits

Reviewing files that changed from the base of the PR and between a062260 and 9275910.

📒 Files selected for processing (1)
  • apps/vscode/src/auth/CloudAuthProvider.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Inline review comments failed to post. This is likely due to GitHub's internal server error or limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/vscode/src/auth/CloudAuthProvider.ts`:
- Around line 43-56: Update resolveCloudAppUrl so its parse-failure path no
longer returns the hardcoded production URL; instead fail safely by returning
the configured cloudApiUrl unchanged or using the existing flow to suppress the
Cloud button. Preserve the current URL transformation for valid configured
deployments.
- Around line 214-225: Separate the authentication and cleanup flows in the
method containing the temporary RocketRideClient: keep connect() failures
handled by the existing sign-in error path, but run tempClient.disconnect() in
independent cleanup handling after a successful connection. Ensure disconnect
errors do not return early or prevent the subsequent storeToken and
storeUserName operations from processing the successful ConnectResult.
- Around line 137-174: Update handleGoogleOAuth so error and missing-token
responses notify the matching pending Google OAuth waiter before returning,
rather than deleting it without resolution. Add or reuse an explicit failure
callback/error response alongside the success callback established by
setPendingGoogleOAuth, while preserving nodeId matching and sole-waiter fallback
behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 445719a7-6940-4c2c-a2c5-0ff25a9c6b43

📥 Commits

Reviewing files that changed from the base of the PR and between a062260 and 9275910.

📒 Files selected for processing (1)
  • apps/vscode/src/auth/CloudAuthProvider.ts
🛑 Comments failed to post (3)
apps/vscode/src/auth/CloudAuthProvider.ts (3)

43-56: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Fallback still hardcodes production, contrary to the PR feedback.

resolveCloudAppUrl derives the URL from the configured deployment on the happy path, but on parse failure it falls back to a hardcoded 'https://cloud.rocketride.ai/'. If ROCKETRIDE_URI is set but malformed on a staging/dev deployment, this still sends the user to production — the exact issue Rod-Christensen flagged. Prefer failing safe (e.g., return the raw cloudApiUrl unmodified, or skip the "Open RocketRide Cloud" button) rather than defaulting to production.

🔧 Suggested fix
 	} catch {
-		return 'https://cloud.rocketride.ai/';
+		// Fall back to the raw configured endpoint rather than assuming production.
+		return cloudApiUrl;
 	}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

function resolveCloudAppUrl(cloudApiUrl: string): string {
	try {
		const url = new URL(RocketRideClient.normalizeUri(cloudApiUrl));
		if (url.hostname.startsWith('api.')) {
			url.hostname = `cloud.${url.hostname.slice('api.'.length)}`;
		}
		url.pathname = '/';
		url.search = '';
		url.hash = '';
		return url.toString();
	} catch {
		// Fall back to the raw configured endpoint rather than assuming production.
		return cloudApiUrl;
	}
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/vscode/src/auth/CloudAuthProvider.ts` around lines 43 - 56, Update
resolveCloudAppUrl so its parse-failure path no longer returns the hardcoded
production URL; instead fail safely by returning the configured cloudApiUrl
unchanged or using the existing flow to suppress the Cloud button. Preserve the
current URL transformation for valid configured deployments.

137-174: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== CloudAuthProvider outline ==\n'
ast-grep outline apps/vscode/src/auth/CloudAuthProvider.ts --view expanded || true

printf '\n== Relevant usages of setPendingGoogleOAuth / pendingGoogleOAuth ==\n'
rg -n "setPendingGoogleOAuth|pendingGoogleOAuth|handleGoogleOAuth|GoogleOAuth" apps/vscode/src -A3 -B3 || true

printf '\n== File size ==\n'
wc -l apps/vscode/src/auth/CloudAuthProvider.ts

Repository: rocketride-org/rocketride-server

Length of output: 6076


🏁 Script executed:

#!/bin/bash
set -euo pipefail

sed -n '1,260p' apps/vscode/src/auth/CloudAuthProvider.ts | cat -n

Repository: rocketride-org/rocketride-server

Length of output: 11652


🏁 Script executed:

#!/bin/bash
set -euo pipefail
sed -n '1,260p' apps/vscode/src/auth/CloudAuthProvider.ts | cat -n

Repository: rocketride-org/rocketride-server

Length of output: 11652


🏁 Script executed:

#!/bin/bash
set -euo pipefail

sed -n '470,560p' apps/vscode/src/providers/ProjectProvider.ts | cat -n

Repository: rocketride-org/rocketride-server

Length of output: 4470


🏁 Script executed:

#!/bin/bash
set -euo pipefail
sed -n '470,560p' apps/vscode/src/providers/ProjectProvider.ts | cat -n

Repository: rocketride-org/rocketride-server

Length of output: 4470


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== project:oauthTokens handling ==\n'
rg -n "project:oauthTokens|oauthTokens|Google sign-in|waiting for sign-in|sign-in" apps/vscode/src/providers/ProjectProvider.ts apps/vscode/src -A4 -B4 || true

printf '\n== nearby webview messaging flow ==\n'
sed -n '560,760p' apps/vscode/src/providers/ProjectProvider.ts | cat -n

Repository: rocketride-org/rocketride-server

Length of output: 33660


Handle Google sign-in failures before clearing the waiter. setPendingGoogleOAuth() only feeds project:oauthTokens, so the error/!tokens returns here drop the one-shot callback and leave the panel waiting forever. Send a failure response before returning, or add an explicit error callback.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/vscode/src/auth/CloudAuthProvider.ts` around lines 137 - 174, Update
handleGoogleOAuth so error and missing-token responses notify the matching
pending Google OAuth waiter before returning, rather than deleting it without
resolution. Add or reuse an explicit failure callback/error response alongside
the success callback established by setPendingGoogleOAuth, while preserving
nodeId matching and sole-waiter fallback behavior.

214-225: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Cleanup (disconnect) failure is conflated with auth failure, masking a successful sign-in.

tempClient.disconnect() shares the same try as connect(). If connect() succeeds but disconnect() throws (e.g. transport already closed), execution jumps to the catch, shows a misleading "RocketRide Cloud sign-in failed" message, and returns before storeToken/storeUserName run — even though the user did authenticate successfully. Cleanup errors shouldn't abort a successful auth result.

🔧 Suggested fix
 		let result: ConnectResult;
+		const tempClient = new RocketRideClient({ persist: false });
 		try {
-			const tempClient = new RocketRideClient({ persist: false });
 			result = await tempClient.connect({ code, verifier, redirectUri: REDIRECT_URI }, { uri: cloudUrl });
-
-			// Disconnect immediately — we only needed the auth result
-			await tempClient.disconnect();
 		} catch (error) {
 			const msg = error instanceof Error ? error.message : String(error);
 			vscode.window.showErrorMessage(`RocketRide Cloud sign-in failed: ${msg}`);
 			return;
+		} finally {
+			// Disconnect immediately — we only needed the auth result. Best-effort;
+			// don't let cleanup errors mask a successful auth result.
+			try {
+				await tempClient.disconnect();
+			} catch {
+				/* ignore cleanup errors */
+			}
 		}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

		let result: ConnectResult;
		const tempClient = new RocketRideClient({ persist: false });
		try {
			result = await tempClient.connect({ code, verifier, redirectUri: REDIRECT_URI }, { uri: cloudUrl });
		} catch (error) {
			const msg = error instanceof Error ? error.message : String(error);
			vscode.window.showErrorMessage(`RocketRide Cloud sign-in failed: ${msg}`);
			return;
		} finally {
			// Disconnect immediately — we only needed the auth result. Best-effort;
			// don't let cleanup errors mask a successful auth result.
			try {
				await tempClient.disconnect();
			} catch {
				/* ignore cleanup errors */
			}
		}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/vscode/src/auth/CloudAuthProvider.ts` around lines 214 - 225, Separate
the authentication and cleanup flows in the method containing the temporary
RocketRideClient: keep connect() failures handled by the existing sign-in error
path, but run tempClient.disconnect() in independent cleanup handling after a
successful connection. Ensure disconnect errors do not return early or prevent
the subsequent storeToken and storeUserName operations from processing the
successful ConnectResult.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

module:vscode VS Code extension

Projects

None yet

Development

Successfully merging this pull request may close these issues.

VS Code extension: cloud sign-in shows "no token received" for users without a RocketRide account (should guide them to sign up)

2 participants