[backport cloud/1.37] feat: add per-tab workspace authentication infrastructure (#8089)

Backport of #8073 to `cloud/1.37`

Automatically created by backport workflow.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8089-backport-cloud-1-37-feat-add-per-tab-workspace-authentication-infrastructure-2ea6d73d36508133ace5f3b984f5ae96)
by [Unito](https://www.unito.io)

Co-authored-by: Christian Byrne <cbyrne@comfy.org>
Co-authored-by: anthropic/claude <noreply@anthropic.com>
Co-authored-by: Amp <amp@ampcode.com>
Co-authored-by: Simula_r <18093452+simula-r@users.noreply.github.com>
This commit is contained in:
Comfy Org PR Bot
2026-01-22 09:28:37 +09:00
committed by GitHub
parent f074243dda
commit abb2b15ea1
12 changed files with 1392 additions and 36 deletions

View File

@@ -1,5 +1,6 @@
import { api } from '@/scripts/api'
import { isCloud } from '@/platform/distribution/types'
import { remoteConfig } from '@/platform/remoteConfig/remoteConfig'
import { api } from '@/scripts/api'
import { useFirebaseAuthStore } from '@/stores/firebaseAuthStore'
/**
@@ -10,31 +11,59 @@ export const useSessionCookie = () => {
/**
* Creates or refreshes the session cookie.
* Called after login and on token refresh.
*
* When team_workspaces_enabled is true, uses Firebase token directly
* (since getAuthHeader() returns workspace token which shouldn't be used for session creation).
* When disabled, uses getAuthHeader() for backward compatibility.
*/
const createSession = async (): Promise<void> => {
if (!isCloud) return
const authStore = useFirebaseAuthStore()
const authHeader = await authStore.getAuthHeader()
try {
const authStore = useFirebaseAuthStore()
if (!authHeader) {
throw new Error('No auth header available for session creation')
}
let authHeader: Record<string, string>
const response = await fetch(api.apiURL('/auth/session'), {
method: 'POST',
credentials: 'include',
headers: {
...authHeader,
'Content-Type': 'application/json'
if (remoteConfig.value.team_workspaces_enabled) {
const firebaseToken = await authStore.getIdToken()
if (!firebaseToken) {
console.warn(
'Failed to create session cookie:',
'No Firebase token available for session creation'
)
return
}
authHeader = { Authorization: `Bearer ${firebaseToken}` }
} else {
const header = await authStore.getAuthHeader()
if (!header) {
console.warn(
'Failed to create session cookie:',
'No auth header available for session creation'
)
return
}
authHeader = header
}
})
if (!response.ok) {
const errorData = await response.json().catch(() => ({}))
throw new Error(
`Failed to create session: ${errorData.message || response.statusText}`
)
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(() => ({}))
console.warn(
'Failed to create session cookie:',
errorData.message || response.statusText
)
}
} catch (error) {
console.warn('Failed to create session cookie:', error)
}
}
@@ -45,16 +74,21 @@ export const useSessionCookie = () => {
const deleteSession = async (): Promise<void> => {
if (!isCloud) return
const response = await fetch(api.apiURL('/auth/session'), {
method: 'DELETE',
credentials: 'include'
})
try {
const response = await fetch(api.apiURL('/auth/session'), {
method: 'DELETE',
credentials: 'include'
})
if (!response.ok) {
const errorData = await response.json().catch(() => ({}))
throw new Error(
`Failed to delete session: ${errorData.message || response.statusText}`
)
if (!response.ok) {
const errorData = await response.json().catch(() => ({}))
console.warn(
'Failed to delete session cookie:',
errorData.message || response.statusText
)
}
} catch (error) {
console.warn('Failed to delete session cookie:', error)
}
}