From c41a7bf3d3c4bfa5b82803a5474287f8332459b8 Mon Sep 17 00:00:00 2001 From: jangwoong Date: Wed, 8 Jul 2026 10:45:53 +0900 Subject: [PATCH] =?UTF-8?q?[as=20frontend]=20device-id=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=ED=9B=84=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/cs/app/api/proxy/[...url]/route.ts | 15 +++++++++++++ packages/common/network/client.ts | 28 +++++++++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/apps/cs/app/api/proxy/[...url]/route.ts b/apps/cs/app/api/proxy/[...url]/route.ts index 0929ca57c..8e9a39cae 100644 --- a/apps/cs/app/api/proxy/[...url]/route.ts +++ b/apps/cs/app/api/proxy/[...url]/route.ts @@ -20,6 +20,16 @@ async function handler( "Content-Type": "application/json", "X-Site-Id": SITE_ID, }; + + // X-Device-Id 중계 로직 (헤더 또는 쿠키에서 획득) + const deviceId = + request.headers.get("x-device-id") || + request.headers.get("X-Device-Id") || + cookieStore.get("device-id")?.value; + if (deviceId) { + headers["X-Device-Id"] = deviceId; + } + let body = {}; const isRefreshHandler = params.url.includes("refresh"); @@ -45,6 +55,11 @@ async function handler( }); if (!result.ok) { + console.error(`[BFF Proxy Error] Backend returned status ${result.status} for ${params.url.join("/")}`); + try { + const errorText = await result.text(); + console.error(`[BFF Proxy Error Body] ${errorText}`); + } catch (err) {} return NextResponse.json( { message: "Invalid Credentials" }, { status: 401 }, diff --git a/packages/common/network/client.ts b/packages/common/network/client.ts index 6b39a33fa..59dc94b24 100644 --- a/packages/common/network/client.ts +++ b/packages/common/network/client.ts @@ -24,6 +24,21 @@ class Client { }); this.axiosInstance.interceptors.request.use((config) => { + // X-Device-Id 자동 주입 로직 (기기에 고유한 UUID 세팅 및 쿠키/로컬스토리지 보관) + let deviceId = Cookies.get("device-id"); + if (!deviceId && typeof window !== "undefined") { + deviceId = localStorage.getItem("device-id") || undefined; + if (!deviceId) { + deviceId = generateUUID(); + localStorage.setItem("device-id", deviceId); + } + Cookies.set("device-id", deviceId, { expires: 365, path: "/" }); + } + + if (deviceId) { + config.headers["X-Device-Id"] = deviceId; + } + const token = Cookies.get(CLAIM_NAME); const userId = Cookies.get(AUTH_USER_ID); @@ -87,3 +102,16 @@ class Client { export type { ClientConfig }; export { Client }; + +// 기기 식별을 위한 안전한 v4 UUID 생성 폴백 헬퍼 함수 +function generateUUID(): string { + if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") { + return crypto.randomUUID(); + } + return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function (c) { + const r = (Math.random() * 16) | 0; + const v = c === "x" ? r : (r & 0x3) | 0x8; + return v.toString(16); + }); +} +