// Dedicated app login (NEW). Reuses the FULL existing login flow (auto-finalize, scout tokens, // mobile-worker gate, …) by proxying to /api/idempiere-auth/login internally — so that complex, // battle-tested logic is neither duplicated nor modified. The ONLY thing this adds is surfacing // `refresh_token` in the response body, which the web flow deliberately keeps httpOnly. The app // stores token + refresh_token itself (it cannot use cross-origin httpOnly cookies); the web // endpoint and its security posture are completely untouched. export default defineEventHandler(async (event) => { const body = await readBody(event) // Internal call → runs the whole existing login pipeline. It returns HTTP 200 with a data object // in both success ({ token, user, … }) and auth-failure ({ status, message }) cases, so this // does not throw on bad credentials — we just pass the shape straight back to the app. const res: any = await $fetch.raw('/api/idempiere-auth/login', { method: 'POST', body }) const data: any = res?._data ?? {} // Surface refresh_token from the Set-Cookie (logship_rt) the inner login issued. The inner // Set-Cookie does NOT leak to this app response (the app uses no server cookies); we only read it. if (data?.token && !data.refresh_token) { let cookies: string[] = [] try { cookies = (res.headers?.getSetCookie?.() as string[]) ?? [] } catch { cookies = [] } if (!cookies.length) { const raw = res.headers?.get?.('set-cookie') if (raw) cookies = Array.isArray(raw) ? raw : [raw] } for (const c of cookies) { const m = /(?:^|[;,\s])logship_rt=([^;]+)/.exec(c) if (m) { data.refresh_token = decodeURIComponent(m[1]); break } } } return data })