mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-02-06 16:10:09 +00:00
fix: prevent unwanted login redirects during WebSocket reconnection (#6410)
## 🐛 Problem Users were experiencing the following issues during WebSocket reconnection: 1. Automatic redirect to login page after "Reconnecting" toast message appears 2. Automatic re-login after a few seconds, returning to the main interface 3. This cycle repeats, severely degrading user experience ## 🔍 Root Cause Analysis ### 1. Router Guard Catching Too Many Errors ```typescript // Problematic code try { const { getUserCloudStatus, getSurveyCompletedStatus } = await import('@/api/auth') const userStatus = await getUserCloudStatus() // ... } catch (error) { // All types of errors are caught here return next({ name: 'cloud-user-check' }) } ``` With dynamic import inside the try block, the following were all being caught: - Errors during `@/api/auth` module loading - Runtime errors from the API singleton - Actual API call errors Everything was caught and redirected to `cloud-user-check`. ### 2. Full Page Reload in UserCheckView ```typescript // Problematic code window.location.href = '/' // Full page reload! ``` This caused: - Loss of SPA benefits - Firebase Auth re-initialization → temporarily null user - Router guard re-execution → potential for another redirect ## ✅ Solution ### 1. router.ts: Move dynamic import outside try block ```typescript // After fix const { getUserCloudStatus, getSurveyCompletedStatus } = await import('@/api/auth') try { // Only API calls inside try const userStatus = await getUserCloudStatus() // ... } catch (error) { // Now only catches pure API call errors return next({ name: 'cloud-user-check' }) } ``` ### 2. UserCheckView.vue: Use SPA routing ```typescript // After fix await router.replace('/') // Use Vue Router instead of window.location.href ``` 🤖 Generated with [Claude Code](https://claude.ai/code) ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-6410-fix-prevent-unwanted-login-redirects-during-WebSocket-reconnection-29c6d73d3650818a8a1acbdcebd2f703) by [Unito](https://www.unito.io) --------- Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: GitHub Action <action@github.com>
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import { computed, ref, watch } from 'vue'
|
||||
import { createSharedComposable } from '@vueuse/core'
|
||||
import { computed, ref, watch } from 'vue'
|
||||
|
||||
import { useCurrentUser } from '@/composables/auth/useCurrentUser'
|
||||
import { useFirebaseAuthActions } from '@/composables/auth/useFirebaseAuthActions'
|
||||
|
||||
@@ -74,7 +74,7 @@ const {
|
||||
}
|
||||
|
||||
// User is fully onboarded
|
||||
window.location.href = '/'
|
||||
await router.replace('/')
|
||||
}),
|
||||
null,
|
||||
{ resetOnExecute: false }
|
||||
|
||||
@@ -183,12 +183,11 @@ router.beforeEach(async (to, _from, next) => {
|
||||
// User is logged in - check if they need onboarding
|
||||
// For root path, check actual user status to handle waitlisted users
|
||||
if (!isElectron() && isLoggedIn && to.path === '/') {
|
||||
// Import auth functions dynamically to avoid circular dependency
|
||||
const { getUserCloudStatus, getSurveyCompletedStatus } = await import(
|
||||
'@/api/auth'
|
||||
)
|
||||
try {
|
||||
// Import auth functions dynamically to avoid circular dependency
|
||||
const { getUserCloudStatus, getSurveyCompletedStatus } = await import(
|
||||
'@/api/auth'
|
||||
)
|
||||
|
||||
// Check user's actual status
|
||||
const userStatus = await getUserCloudStatus()
|
||||
const surveyCompleted = await getSurveyCompletedStatus()
|
||||
|
||||
@@ -433,8 +433,12 @@ export class ComfyApi extends EventTarget {
|
||||
await this.#waitForAuthInitialization()
|
||||
|
||||
// Add Firebase JWT token if user is logged in
|
||||
// Force refresh token on reconnection to avoid 401 errors
|
||||
const isReconnecting =
|
||||
options.headers && 'X-Reconnecting' in options.headers
|
||||
try {
|
||||
const authHeader = await useFirebaseAuthStore().getAuthHeader()
|
||||
const authHeader =
|
||||
await useFirebaseAuthStore().getAuthHeader(isReconnecting)
|
||||
if (authHeader) {
|
||||
if (Array.isArray(options.headers)) {
|
||||
for (const [key, value] of Object.entries(authHeader)) {
|
||||
@@ -542,9 +546,10 @@ export class ComfyApi extends EventTarget {
|
||||
let existingSession = window.name
|
||||
|
||||
// Get auth token if available
|
||||
// Force refresh on reconnect to avoid stale tokens
|
||||
let authToken: string | undefined
|
||||
try {
|
||||
authToken = await useFirebaseAuthStore().getIdToken()
|
||||
authToken = await useFirebaseAuthStore().getIdToken(isReconnect)
|
||||
} catch (error) {
|
||||
// Continue without auth token if there's an error
|
||||
console.warn('Could not get auth token for WebSocket connection:', error)
|
||||
|
||||
@@ -106,10 +106,12 @@ export const useFirebaseAuthStore = defineStore('firebaseAuth', () => {
|
||||
}
|
||||
})
|
||||
|
||||
const getIdToken = async (): Promise<string | undefined> => {
|
||||
const getIdToken = async (
|
||||
forceRefresh = false
|
||||
): Promise<string | undefined> => {
|
||||
if (!currentUser.value) return
|
||||
try {
|
||||
return await currentUser.value.getIdToken()
|
||||
return await currentUser.value.getIdToken(forceRefresh)
|
||||
} catch (error: unknown) {
|
||||
if (
|
||||
error instanceof FirebaseError &&
|
||||
@@ -140,9 +142,11 @@ export const useFirebaseAuthStore = defineStore('firebaseAuth', () => {
|
||||
* - An ApiKeyAuthHeader with X-API-KEY if API key exists
|
||||
* - null if neither authentication method is available
|
||||
*/
|
||||
const getAuthHeader = async (): Promise<AuthHeader | null> => {
|
||||
const getAuthHeader = async (
|
||||
forceRefresh = false
|
||||
): Promise<AuthHeader | null> => {
|
||||
// If available, set header with JWT used to identify the user to Firebase service
|
||||
const token = await getIdToken()
|
||||
const token = await getIdToken(forceRefresh)
|
||||
if (token) {
|
||||
return {
|
||||
Authorization: `Bearer ${token}`
|
||||
|
||||
Reference in New Issue
Block a user