// client/src/services/apiClient.js /** * Centralized API client * Enforces auth contract: * - POST /api/auth/session -> Entra JWT (Authorization: Bearer ) * - All other /api/* -> Session token (Authorization: Bearer ) */ export async function callApi({ url, method = 'GET', body, entraToken, sessionToken }) { const headers = { 'Content-Type': 'application/json' }; // ---- AUTH CONTRACT ---- if (url.startsWith('/api/auth/session')) { if (!entraToken) { throw new Error('callApi: entraToken required for /api/auth/session'); } headers['Authorization'] = `Bearer ${entraToken}`; } else if (url.startsWith('/api/')) { if (!sessionToken) { throw new Error('callApi: sessionToken required for authenticated API call'); } headers['Authorization'] = `Bearer ${sessionToken}`; // Optional but useful for server-side correlation headers['X-Requested-With'] = 'USIM-AdPlatform-Client'; } const resp = await fetch(url, { method, headers, body: body ? JSON.stringify(body) : undefined }); // Handle auth failures centrally if (resp.status === 401) { const text = await resp.text(); throw new Error(`API 401: ${text}`); } if (!resp.ok) { const text = await resp.text(); throw new Error(`API ${resp.status}: ${text}`); } return resp.json(); }