From 749fb3a5c1e626ed44d1ac74eda7cdd7c8a551fa Mon Sep 17 00:00:00 2001 From: DhanushSantosh Date: Sun, 18 Jan 2026 21:23:18 +0530 Subject: [PATCH] fix: add token query parameter support to auth middleware for web mode image loading The /api/fs/image endpoint requires authentication, but when loading images via CSS background-image or img tags, only query parameters can be used (headers cannot be set). Web mode passes the session token as a query parameter (?token=...), but the auth middleware didn't recognize it, causing image requests to fail. This fix adds support for the 'token' query parameter in the checkAuthentication function, allowing the auth middleware to validate web mode session tokens when they're passed as query parameters. Now image loads work correctly in web mode by: 1. Client passes session token in URL: ?token={sessionToken} 2. Auth middleware recognizes and validates the token query parameter 3. Image endpoint successfully serves the image after authentication This fixes the issue where kanban board background images were not visible in web mode. Co-Authored-By: Claude Haiku 4.5 --- apps/server/src/lib/auth.ts | 14 ++++++- apps/server/src/routes/fs/routes/image.ts | 50 +---------------------- 2 files changed, 13 insertions(+), 51 deletions(-) diff --git a/apps/server/src/lib/auth.ts b/apps/server/src/lib/auth.ts index 4626ed25..ea9aa42a 100644 --- a/apps/server/src/lib/auth.ts +++ b/apps/server/src/lib/auth.ts @@ -320,6 +320,15 @@ function checkAuthentication( return { authenticated: false, errorType: 'invalid_api_key' }; } + // Check for session token in query parameter (web mode - needed for image loads) + const queryToken = query.token; + if (queryToken) { + if (validateSession(queryToken)) { + return { authenticated: true }; + } + return { authenticated: false, errorType: 'invalid_session' }; + } + // Check for session cookie (web mode) const sessionToken = cookies[SESSION_COOKIE_NAME]; if (sessionToken && validateSession(sessionToken)) { @@ -335,8 +344,9 @@ function checkAuthentication( * Accepts either: * 1. X-API-Key header (for Electron mode) * 2. X-Session-Token header (for web mode with explicit token) - * 3. apiKey query parameter (fallback for cases where headers can't be set) - * 4. Session cookie (for web mode) + * 3. apiKey query parameter (fallback for Electron, cases where headers can't be set) + * 4. token query parameter (fallback for web mode, needed for image loads via CSS/img tags) + * 5. Session cookie (for web mode) */ export function authMiddleware(req: Request, res: Response, next: NextFunction): void { const result = checkAuthentication( diff --git a/apps/server/src/routes/fs/routes/image.ts b/apps/server/src/routes/fs/routes/image.ts index 97187528..32f3b3cb 100644 --- a/apps/server/src/routes/fs/routes/image.ts +++ b/apps/server/src/routes/fs/routes/image.ts @@ -1,7 +1,7 @@ /** * GET /image endpoint - Serve image files * - * Requires authentication via: + * Requires authentication via auth middleware: * - apiKey query parameter (Electron mode) * - token query parameter (web mode) * - session cookie (web mode) @@ -13,21 +13,11 @@ import type { Request, Response } from 'express'; import * as secureFs from '../../../lib/secure-fs.js'; import path from 'path'; import { PathNotAllowedError } from '@automaker/platform'; -import { validateApiKey, validateSession } from '../../../lib/auth.js'; import { getErrorMessage, logError } from '../common.js'; -const SESSION_COOKIE_NAME = 'automaker_session'; - export function createImageHandler() { return async (req: Request, res: Response): Promise => { try { - // Authenticate the request - const isAuthenticated = checkImageAuthentication(req); - if (!isAuthenticated) { - res.status(401).json({ success: false, error: 'Authentication required' }); - return; - } - const { path: imagePath, projectPath } = req.query as { path?: string; projectPath?: string; @@ -81,41 +71,3 @@ export function createImageHandler() { } }; } - -/** - * Check if image request is authenticated - * Supports multiple authentication methods - */ -function checkImageAuthentication(req: Request): boolean { - // Check for API key in header (Electron mode) - const headerKey = req.get('x-api-key'); - if (headerKey && validateApiKey(headerKey)) { - return true; - } - - // Check for session token in header (web mode) - const sessionTokenHeader = req.get('x-session-token'); - if (sessionTokenHeader && validateSession(sessionTokenHeader)) { - return true; - } - - // Check for API key in query parameter (fallback) - const queryKey = req.query.apiKey as string | undefined; - if (queryKey && validateApiKey(queryKey)) { - return true; - } - - // Check for session token in query parameter (web mode with token) - const queryToken = req.query.token as string | undefined; - if (queryToken && validateSession(queryToken)) { - return true; - } - - // Check for session cookie (web mode) - const sessionCookie = req.cookies?.[SESSION_COOKIE_NAME]; - if (sessionCookie && validateSession(sessionCookie)) { - return true; - } - - return false; -}