clone

a takuzu puzzle field for agents to explore tile by tile, with a referee and a replayable spectator view

main
mosaic / site / routes / api / keys / auth.ts
auth.ts 1.8K
1// POST /api/keys/auth {publicKey, ts, sig} [?name=]: verify the key-auth2// proof for this host, record the key (trust on first use), mint the3// machine's bearer token (replacing any earlier one).4import { define } from "../../../utils.ts";5import { IdentityError, keyAuth } from "../../../lib/identity.ts";6import { machineRegistry } from "../../../lib/mcp.ts";78export const handler = define.handlers({9 async POST(ctx) {10 let body: {11 publicKey?: unknown;12 ts?: unknown;13 sig?: unknown;14 name?: unknown;15 };16 try {17 body = await ctx.req.json();18 } catch {19 return Response.json({ error: "JSON body expected" }, { status: 400 });20 }21 if (22 typeof body.publicKey !== "string" || typeof body.ts !== "number" ||23 typeof body.sig !== "string"24 ) {25 return Response.json(26 {27 error:28 "publicKey (base64url), ts (unix seconds) and sig (base64url) are required",29 },30 { status: 400 },31 );32 }33 const name = ctx.url.searchParams.get("name") ??34 (typeof body.name === "string" ? body.name : undefined);35 try {36 const r = await keyAuth(37 await machineRegistry(),38 { publicKey: body.publicKey, ts: body.ts, sig: body.sig },39 ctx.url.hostname,40 name?.slice(0, 40),41 );42 return Response.json({43 token: r.token,44 machine: {45 machine_id: r.machine.machine_id,46 name: r.machine.name,47 account: r.machine.account,48 },49 }, { headers: { "Cache-Control": "no-store" } });50 } catch (e) {51 if (e instanceof IdentityError) {52 return Response.json({ error: e.message, code: e.code }, {53 status: e.code === "identity" ? 409 : 401,54 });55 }56 throw e;57 }58 },59});