Skip to content

Commit f1c28ba

Browse files
committed
fix: improve authentication reliability in Windsurf
- Add enhanced error handling and logging for credential storage/retrieval - Implement periodic credential checking as fallback for Windsurf compatibility - Force credential reload after authentication callback to ensure state transition - Add manual credential check with timeout after successful authentication - Improve secrets API error handling for different VSCode-compatible editors Fixes #5914
1 parent a6e16e8 commit f1c28ba

File tree

1 file changed

+75
-12
lines changed

1 file changed

+75
-12
lines changed

packages/cloud/src/auth/WebAuthService.ts

Lines changed: 75 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -115,18 +115,25 @@ export class WebAuthService extends EventEmitter<AuthServiceEvents> implements A
115115

116116
private async handleCredentialsChange(): Promise<void> {
117117
try {
118+
this.log("[auth] Handling credentials change...")
118119
const credentials = await this.loadCredentials()
119120

120121
if (credentials) {
122+
this.log("[auth] Credentials found, checking if they changed")
121123
if (
122124
this.credentials === null ||
123125
this.credentials.clientToken !== credentials.clientToken ||
124126
this.credentials.sessionId !== credentials.sessionId
125127
) {
128+
this.log("[auth] Credentials changed, transitioning to attempting session")
126129
this.transitionToAttemptingSession(credentials)
130+
} else {
131+
this.log("[auth] Credentials unchanged")
127132
}
128133
} else {
134+
this.log("[auth] No credentials found")
129135
if (this.state !== "logged-out") {
136+
this.log("[auth] Transitioning to logged-out state")
130137
this.transitionToLoggedOut()
131138
}
132139
}
@@ -135,6 +142,15 @@ export class WebAuthService extends EventEmitter<AuthServiceEvents> implements A
135142
}
136143
}
137144

145+
/**
146+
* Manually check for credential changes - used as fallback for Windsurf
147+
* where secrets.onDidChange might not work reliably
148+
*/
149+
private async checkCredentialsManually(): Promise<void> {
150+
this.log("[auth] Manually checking credentials...")
151+
await this.handleCredentialsChange()
152+
}
153+
138154
private transitionToLoggedOut(): void {
139155
this.timer.stop()
140156

@@ -191,26 +207,64 @@ export class WebAuthService extends EventEmitter<AuthServiceEvents> implements A
191207
return
192208
}
193209

210+
this.log("[auth] Initializing WebAuthService...")
211+
194212
await this.handleCredentialsChange()
195213

196-
this.context.subscriptions.push(
197-
this.context.secrets.onDidChange((e) => {
198-
if (e.key === this.authCredentialsKey) {
199-
this.handleCredentialsChange()
200-
}
201-
}),
202-
)
214+
// Set up secrets change listener with error handling for Windsurf compatibility
215+
try {
216+
this.context.subscriptions.push(
217+
this.context.secrets.onDidChange((e) => {
218+
if (e.key === this.authCredentialsKey) {
219+
this.log("[auth] Secrets changed, handling credentials change")
220+
this.handleCredentialsChange()
221+
}
222+
}),
223+
)
224+
this.log("[auth] Secrets change listener registered successfully")
225+
} catch (error) {
226+
this.log("[auth] Warning: Failed to register secrets change listener:", error)
227+
// Continue without the listener - we'll rely on manual credential checks
228+
}
229+
230+
// Set up periodic credential check as fallback for Windsurf
231+
const credentialCheckInterval = setInterval(async () => {
232+
if (this.state === "initializing") {
233+
return // Don't check during initialization
234+
}
235+
await this.checkCredentialsManually()
236+
}, 5000) // Check every 5 seconds
237+
238+
// Clean up interval when context is disposed
239+
this.context.subscriptions.push({
240+
dispose: () => {
241+
clearInterval(credentialCheckInterval)
242+
this.log("[auth] Credential check interval cleared")
243+
}
244+
})
245+
246+
this.log("[auth] WebAuthService initialization complete")
203247
}
204248

205249
private async storeCredentials(credentials: AuthCredentials): Promise<void> {
206-
await this.context.secrets.store(this.authCredentialsKey, JSON.stringify(credentials))
250+
try {
251+
await this.context.secrets.store(this.authCredentialsKey, JSON.stringify(credentials))
252+
this.log("[auth] Credentials stored successfully")
253+
} catch (error) {
254+
this.log("[auth] Error storing credentials:", error)
255+
throw new Error(`Failed to store authentication credentials: ${error}`)
256+
}
207257
}
208258

209259
private async loadCredentials(): Promise<AuthCredentials | null> {
210-
const credentialsJson = await this.context.secrets.get(this.authCredentialsKey)
211-
if (!credentialsJson) return null
212-
213260
try {
261+
const credentialsJson = await this.context.secrets.get(this.authCredentialsKey)
262+
if (!credentialsJson) {
263+
this.log("[auth] No credentials found in storage")
264+
return null
265+
}
266+
267+
this.log("[auth] Loading credentials from storage")
214268
const parsedJson = JSON.parse(credentialsJson)
215269
const credentials = authCredentialsSchema.parse(parsedJson)
216270

@@ -221,12 +275,13 @@ export class WebAuthService extends EventEmitter<AuthServiceEvents> implements A
221275
this.log("[auth] Migrated credentials with organizationId")
222276
}
223277

278+
this.log("[auth] Credentials loaded successfully")
224279
return credentials
225280
} catch (error) {
226281
if (error instanceof z.ZodError) {
227282
this.log("[auth] Invalid credentials format:", error.errors)
228283
} else {
229-
this.log("[auth] Failed to parse stored credentials:", error)
284+
this.log("[auth] Failed to load or parse stored credentials:", error)
230285
}
231286
return null
232287
}
@@ -298,6 +353,14 @@ export class WebAuthService extends EventEmitter<AuthServiceEvents> implements A
298353

299354
await this.storeCredentials(credentials)
300355

356+
// Force credential reload and state transition for Windsurf compatibility
357+
await this.handleCredentialsChange()
358+
359+
// Additional manual check after a short delay to ensure state transition
360+
setTimeout(async () => {
361+
await this.checkCredentialsManually()
362+
}, 1000)
363+
301364
vscode.window.showInformationMessage("Successfully authenticated with Roo Code Cloud")
302365
this.log("[auth] Successfully authenticated with Roo Code Cloud")
303366
} catch (error) {

0 commit comments

Comments
 (0)