diff --git a/otel-ui/src/dev/device-auth.ts b/otel-ui/src/dev/device-auth.ts index 40bb89a..b24d03d 100644 --- a/otel-ui/src/dev/device-auth.ts +++ b/otel-ui/src/dev/device-auth.ts @@ -21,15 +21,16 @@ interface DeviceStart { interval?: number; } -const post = (path: string, body: Record) => +// RFC 8628 endpoints take form bodies; /device/refresh takes JSON. +const post = (path: string, body: Record, json = false) => fetch(`/dev-auth${path}`, { method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify(body), + headers: { "Content-Type": json ? "application/json" : "application/x-www-form-urlencoded" }, + body: json ? JSON.stringify(body) : new URLSearchParams(body), }); async function refresh(refreshToken: string): Promise { - const res = await post("/device/refresh", { client_id: CLIENT_ID, refresh_token: refreshToken }); + const res = await post("/device/refresh", { refresh_token: refreshToken }, true); return res.ok ? ((await res.json()) as TokenResponse) : null; } diff --git a/scripts/dev-auth.mjs b/scripts/dev-auth.mjs index 2aacf4a..54978b9 100644 --- a/scripts/dev-auth.mjs +++ b/scripts/dev-auth.mjs @@ -21,11 +21,12 @@ const DIR = join(homedir(), ".go-auth", "dev"); const FILE = join(DIR, `${CLIENT}.json`); const GRANT = "urn:ietf:params:oauth:grant-type:device_code"; -const post = (path, body) => +// RFC 8628 endpoints take form bodies; /device/refresh takes JSON. +const post = (path, body, json = false) => fetch(`${BASE}/api/auth${path}`, { method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify(body), + headers: { "Content-Type": json ? "application/json" : "application/x-www-form-urlencoded" }, + body: json ? JSON.stringify(body) : new URLSearchParams(body), }); async function save(refresh) { @@ -53,7 +54,7 @@ async function login() { return; } if (body.error === "slow_down") interval += 5000; - else if (body.error !== "authorization_pending") throw new Error(body.error ?? `HTTP ${t.status}`); + else if (body.error !== "authorization_pending") throw new Error([body.error ?? `HTTP ${t.status}`, body.error_description].filter(Boolean).join(": ")); } throw new Error("device code expired"); } @@ -66,7 +67,7 @@ async function token() { } catch { throw new Error("not signed in: run `node scripts/dev-auth.mjs login`"); } - const res = await post("/device/refresh", { client_id: CLIENT, refresh_token: stored.refresh_token }); + const res = await post("/device/refresh", { refresh_token: stored.refresh_token }, true); if (!res.ok) throw new Error(`refresh failed (HTTP ${res.status}); run login again`); const body = await res.json(); if (body.refresh_token) await save(body.refresh_token);