Files
ComfyUI_frontend/src/platform/auth/workspace/useWorkspaceSwitch.ts
Christian Byrne 6048fab239 feat: add per-tab workspace authentication infrastructure (#8073)
## Summary
Add workspace authentication composables and types for per-tab workspace
isolation. This infrastructure enables users to work in different
workspaces in different browser tabs.

## Changes
- **useWorkspaceAuth composable** - workspace token management
- Exchange Firebase token for workspace-scoped JWT via `POST
/api/auth/token`
  - Auto-refresh tokens 5 minutes before expiry
  - Per-tab sessionStorage caching
- **useWorkspaceSwitch composable** - workspace switching with unsaved
changes confirmation
- **WorkspaceWithRole/WorkspaceTokenResponse types** - aligned with
backend API
- **firebaseAuthStore.getAuthHeader()** - prioritizes workspace tokens
over Firebase tokens
- **useSessionCookie** - uses Firebase token directly (getIdToken())
since getAuthHeader() now returns workspace token

## Backend Dependency
- `POST /api/auth/token` - exchange Firebase token for workspace token
- `GET /api/workspaces` - list user's workspaces

## Related
- https://github.com/Comfy-Org/ComfyUI_frontend/pull/6295

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

---------

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>
2026-01-15 17:24:48 -08:00

50 lines
1.3 KiB
TypeScript

import { storeToRefs } from 'pinia'
import { useI18n } from 'vue-i18n'
import { useWorkflowStore } from '@/platform/workflow/management/stores/workflowStore'
import { useDialogService } from '@/services/dialogService'
import { useWorkspaceAuthStore } from '@/stores/workspaceAuthStore'
export function useWorkspaceSwitch() {
const { t } = useI18n()
const workspaceAuthStore = useWorkspaceAuthStore()
const { currentWorkspace } = storeToRefs(workspaceAuthStore)
const workflowStore = useWorkflowStore()
const dialogService = useDialogService()
function hasUnsavedChanges(): boolean {
return workflowStore.modifiedWorkflows.length > 0
}
async function switchWithConfirmation(workspaceId: string): Promise<boolean> {
if (currentWorkspace.value?.id === workspaceId) {
return true
}
if (hasUnsavedChanges()) {
const confirmed = await dialogService.confirm({
title: t('workspace.unsavedChanges.title'),
message: t('workspace.unsavedChanges.message'),
type: 'dirtyClose'
})
if (!confirmed) {
return false
}
}
try {
await workspaceAuthStore.switchWorkspace(workspaceId)
window.location.reload()
return true
} catch {
return false
}
}
return {
hasUnsavedChanges,
switchWithConfirmation
}
}