mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-02-07 16:40:05 +00:00
feat: add retry logic for session cookie creation with token refresh
- Add retry mechanism with exponential backoff in useSessionCookie - Support forceRefresh parameter in getAuthHeader and getIdToken - First attempt uses cached token, retries force token refresh - Fixes intermittent 'No auth header available' errors during token refresh Addresses Sentry issue affecting users with authentication timing issues
This commit is contained in:
@@ -10,32 +10,49 @@ export const useSessionCookie = () => {
|
||||
/**
|
||||
* Creates or refreshes the session cookie.
|
||||
* Called after login and on token refresh.
|
||||
* Implements retry logic with token refresh for handling timing issues.
|
||||
*/
|
||||
const createSession = async (): Promise<void> => {
|
||||
if (!isCloud) return
|
||||
|
||||
const authStore = useFirebaseAuthStore()
|
||||
const authHeader = await authStore.getAuthHeader()
|
||||
|
||||
if (!authHeader) {
|
||||
throw new Error('No auth header available for session creation')
|
||||
}
|
||||
// Simple retry with forceRefresh for token timing issues
|
||||
for (let attempt = 0; attempt < 3; attempt++) {
|
||||
// First attempt uses cached token, retries force refresh
|
||||
const authHeader = await authStore.getAuthHeader(attempt > 0)
|
||||
|
||||
const response = await fetch(api.apiURL('/auth/session'), {
|
||||
method: 'POST',
|
||||
credentials: 'include',
|
||||
headers: {
|
||||
...authHeader,
|
||||
'Content-Type': 'application/json'
|
||||
if (authHeader) {
|
||||
// Successfully got auth header, proceed with session creation
|
||||
const response = await fetch(api.apiURL('/auth/session'), {
|
||||
method: 'POST',
|
||||
credentials: 'include',
|
||||
headers: {
|
||||
...authHeader,
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
})
|
||||
|
||||
if (!response.ok) {
|
||||
const errorData = await response.json().catch(() => ({}))
|
||||
throw new Error(
|
||||
`Failed to create session: ${errorData.message || response.statusText}`
|
||||
)
|
||||
}
|
||||
|
||||
return // Success
|
||||
}
|
||||
})
|
||||
|
||||
if (!response.ok) {
|
||||
const errorData = await response.json().catch(() => ({}))
|
||||
throw new Error(
|
||||
`Failed to create session: ${errorData.message || response.statusText}`
|
||||
)
|
||||
// Exponential backoff before retry (except for last attempt)
|
||||
if (attempt < 2) {
|
||||
await new Promise((r) => setTimeout(r, Math.pow(2, attempt) * 500))
|
||||
}
|
||||
}
|
||||
|
||||
// Failed to get auth header after 3 attempts
|
||||
throw new Error(
|
||||
'No auth header available for session creation after retries'
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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 &&
|
||||
@@ -135,14 +137,17 @@ export const useFirebaseAuthStore = defineStore('firebaseAuth', () => {
|
||||
* 1. Firebase authentication token (if user is logged in)
|
||||
* 2. API key (if stored in the browser's credential manager)
|
||||
*
|
||||
* @param forceRefresh - If true, forces a refresh of the Firebase token
|
||||
* @returns {Promise<AuthHeader | null>}
|
||||
* - A LoggedInAuthHeader with Bearer token if Firebase authenticated
|
||||
* - 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