// scenarios/auth.mjs — bearer auth seams: REST 401s, WS rejection. // PROTOCOL.md §Auth: "All requests (WS upgrade and REST) carry // Authorization: Bearer … Daemon rejects with 401 (REST) or closes the WS // (upgrade) on mismatch." import { agentHello, rest, sessionSnapshot, sid, WSSock } from "../lib.mjs"; export async function run(ctx) { const { r, base, token, agentUrl, webUrl } = ctx; const noToken = await rest(base, null, "/api/sessions"); r.check( "REST without token → 401", noToken.status === 401, `got ${noToken.status}`, ); const badToken = await rest(base, "definitely-wrong", "/api/sessions"); r.check( "REST with bad token → 401", badToken.status === 401, `got ${badToken.status}`, ); const goodToken = await rest(base, token, "/api/sessions"); r.check( "REST with correct token → 200", goodToken.status === 200, `got ${goodToken.status}`, ); // Web WS: token arrives as ?token= query param (browsers cannot set headers). const badWeb = new WSSock(`${webUrl}?token=wrong-token`); const webOpened = await badWeb.opened(); r.check( "web WS with bad ?token= rejected before upgrade", !webOpened, "connection accepted", ); badWeb.close(); // Agent WS with bad bearer must be rejected: PROTOCOL.md §Auth requires // closing the upgrade on mismatch (fixed: Routes() wraps /agent/ws in // s.bearerAuth). const badAgent = new WSSock(agentUrl, { headers: { Authorization: `Bearer wrong-token` }, }); const agentOpened = await badAgent.opened(); let welcomed = null; if (agentOpened) { agentHello(badAgent, sessionSnapshot(sid("e2e-auth-bad"))); welcomed = await badAgent.waitForFrame((f) => f.type === "welcome"); } r.check( "agent WS with bad token rejected (closed before welcome)", !agentOpened || welcomed === null, welcomed ? "welcome received despite wrong bearer" : "", ); badAgent.close(); }