From d2a0c9a76d18c33dda0e20de2107970cff1a1356 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Gil=20P=C3=A9rez?= Date: Sun, 19 Apr 2026 14:52:01 +0200 Subject: [PATCH] fix(find): use getUserHeaders() for Immich smart search auth MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The /api/find/search handler was hard-coding `Authorization: Bearer ${currentUser?.accessToken}`. When Power Tools authenticates via `IMMICH_API_KEY` (no cookie session), `accessToken` is undefined and Immich returns 401 — which surfaces in the UI as "No results found", making the feature silently unusable in API-key deployments. This swaps the inline header construction for the existing `getUserHeaders()` helper in `src/helpers/user.helper.ts`, which already handles both modes: `x-api-key` when `isUsingAPIKey`, `Authorization: Bearer …` otherwise. Also adds an explicit 403 when there's no authenticated user, instead of letting the request flow forward with `Bearer undefined`. Repro (before): curl -X POST http://localhost:8001/api/find/search -d '{"query":"beach"}' \ → {"assets":[],"filters":{…},"error":"Failed to fetch assets"} After: same request → 40 assets with embeddings matching "beach" --- src/pages/api/find/search.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/pages/api/find/search.ts b/src/pages/api/find/search.ts index e5fead7..a28217e 100644 --- a/src/pages/api/find/search.ts +++ b/src/pages/api/find/search.ts @@ -4,6 +4,7 @@ import { ASSET_VIDEO_PATH } from "@/config/routes"; import { getCurrentUser } from "@/handlers/serverUtils/user.utils"; import { cleanUpAsset, isFlipped } from "@/helpers/asset.helper"; import { parseFindQuery } from "@/helpers/ai.helper"; +import { getUserHeaders } from "@/helpers/user.helper"; import { person } from "@/schema"; import { Person } from "@/schema/person.schema"; import { inArray } from "drizzle-orm"; @@ -16,6 +17,9 @@ export default async function search( try { const { query } = req.body; const currentUser = await getCurrentUser(req); + if (!currentUser) { + return res.status(403).json({ message: "Not authenticated" }); + } const parsedQuery = await parseFindQuery(query as string); const { personIds } = parsedQuery; @@ -32,10 +36,7 @@ export default async function search( return fetch(url, { method: "POST", body: JSON.stringify({ ...parsedQuery, withExif: true }), - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${currentUser?.accessToken}`, - }, + headers: getUserHeaders(currentUser, { "Content-Type": "application/json" }), }) .then((response) => { if (response.status !== 200) {