## Summary Behind `unified_cloud_auth` (default OFF), flip the two token accessors so every cloud request rides the single Cloud JWT minted in PR2. This is the consumer-flip phase of FE-950: PR2 built the dormant `unifiedToken` slot; this PR makes consumers read it — and surfaces the permanent-auth-failure path that the flip turns from graceful degradation into a hard stop. Stacked on #12704 (PR2), now merged; base is `main`. ## Changes - **What**: - `getAuthHeader()` — flag ON returns `{ Authorization: Bearer <unifiedToken> }` (or `null` if unminted), with **no** Firebase/API-key fallback. Flag OFF keeps the exact workspace → Firebase → API-key cascade. - `getAuthToken()` — flag ON returns the unified Cloud JWT (or `undefined`); flag OFF keeps workspace → Firebase. - Both accessors are the single seam every cloud consumer already routes through, so the flip propagates automatically with **no edits** to `fetchApi` (`scripts/api.ts`), `/customers/*` (authStore), `workspaceApi`, the WebSocket (`api.ts:568`), or backend-node auth (`app.ts:1593`). - **Surface permanent auth failures** (answers @pythongosssss's review on PR2). Under the flag there is no Firebase fallback, so a silent `clearUnifiedContext()` wipe would strand every cloud request until manual re-login — unlike the legacy path, which degrades to the Firebase token. `refreshUnified()` and `mintAtLogin()` now emit a user-facing error toast (keyed by error code off the existing `workspaceAuth.errors` i18n) on the permanent codes (`ACCESS_DENIED` / `WORKSPACE_NOT_FOUND` / `INVALID_FIREBASE_TOKEN` / `NOT_AUTHENTICATED`). `mintAtLogin()` now resolves `false` on a permanent failure instead of rejecting an unhandled `void`ed promise. Transient failures stay silent (proactive refresh still retries). Also trims the verbose unified-lifecycle comments flagged in review. - **Breaking**: None. Flag OFF is byte-for-byte the current cascade. ## Review Focus - **Single token, no fallback under the flag.** Tests assert `getAuthHeader`/`getAuthToken` return only the unified token and never call `getIdToken` or the API-key store; they return `null`/`undefined` (not a fallback) when the token is unminted. - **Surfacing, not recovery.** This PR makes the terminal state *visible* (toast); the existing router auth-guard still redirects to login on the next navigation. Active recovery (automatic re-mint on 401) stays in the deferred safety-net PR so the toast is never a dead-end "please re-login" with the fix one PR away. - **Flag-OFF parity.** The full existing cascade suite runs with `unifiedCloudAuthEnabled = false` (the `beforeEach` default) and stays green. ## Deferred (intentional) - **`acceptInvite` is left unchanged — still Firebase-authed.** It is the one cloud call that intentionally keeps the raw Firebase token, because the invite is accepted *before* the user is a member of the target workspace. Promoting it to the unified Cloud JWT first needs a quick check that `POST /invites/:token/accept` accepts a personal-scoped Cloud JWT for a not-yet-member; deferred until that is verified. `getFirebaseAuthHeader` / `getFirebaseAuthHeaderOrThrow` stay defined (their removal belongs to the later cleanup ticket, FE-951). No `workspaceApi.ts` change in this PR. - **The reactive 401 re-mint + retry safety net is a follow-up.** A clean place to intercept a `401` and re-mint once does not exist yet: cloud requests use raw `fetch` (`/customers/*`, `/auth/token`) plus several independent axios clients (`workspaceApi`, `customerEventsService`, registry, manager), with no shared response interceptor. PR2's `remintUnifiedOnce()` primitive is ready, and the proactive buffer-based refresh (`refreshUnified`) already covers the common token-*expiry* case, so this cross-cutting safety net (plus deciding whether the surfacing toast escalates to a guided re-login CTA once remint exists) lands in its own focused PR before any production rollout. Note this is orthogonal to the surfacing above: proactive refresh prevents expiry; it cannot prevent *revocation*, which is exactly what triggers the now-surfaced permanent-error path. ## Tests - Extended `authTokenPriority.test.ts`: flag-ON `getAuthHeader` returns only the unified JWT (Firebase + API-key + workspace untouched) and `null` when unminted; flag-ON `getAuthToken` returns the unified JWT (not Firebase) and `undefined` when unminted. Existing cascade tests prove flag-OFF parity. - Added to `useWorkspaceAuth.test.ts` (red-green + regression lock): a permanent refresh error toasts the **correct i18n key for each of the four permanent codes** (`it.for` over 403/404/401 + a lost-Firebase-token `NOT_AUTHENTICATED` case) and clears the slot; a permanent login-mint error toasts and resolves `false`. Negative guards prove the surfacing is **error-only and flag-scoped**: a transient (5xx) refresh does **not** toast and keeps the slot, a **successful** re-mint does not toast, and the unified lifecycle **never toasts when the flag is OFF** (even against a rejecting backend). ## Red-Green Verification | Commit | CI | Purpose | |--------|-----|---------| | `test: cover permanent unified-auth error surfacing` | 🔴 Red ([run](https://github.com/Comfy-Org/ComfyUI_frontend/actions/runs/27455949404)) | Proves the tests catch the silent-failure gap | | `fix: surface permanent unified-auth errors instead of failing silently` | 🟢 Green ([run](https://github.com/Comfy-Org/ComfyUI_frontend/actions/runs/27456200098)) | Proves the surfacing resolves it | Part of FE-950 (single Cloud-JWT provider at login, Phase 1).
Scripts Directory Documentation
This directory contains TypeScript code inherited from the legacy ComfyUI JavaScript frontend project. The code has been migrated from JavaScript to TypeScript while maintaining compatibility with the original functionality.
When implementing new features, prefer using the new Vue3 system over the legacy scripts.
Key Components
ComfyApi (api.ts)
Main API client class that handles communication with the ComfyUI backend. Provides methods for:
- Queue management
- Model operations
- Extension handling
- WebSocket communication
- User data management
ComfyApp (app.ts)
Core application class that manages:
- Graph manipulation
- Node management
- Canvas interactions
- Extension system
- Workflow state
UI Components (ui/)
Collection of reusable UI components including:
- Buttons and button groups
- Popups and dialogs
- Draggable lists
- Image previews
- Menu system
- Settings dialog
Integration with Vite
All TypeScript exports are shimmed through Vite configuration to maintain compatibility with the legacy JavaScript codebase. The shimming logic can be found in vite.config.mts.
Legacy Compatibility
This codebase maintains compatibility with the original ComfyUI Legacy Frontend while providing TypeScript type safety and modern development features.
For users wanting to fall back to the legacy frontend, use the command line argument:
--front-end-version Comfy-Org/ComfyUI_legacy_frontend@latest