import express from "express"; import cors from "cors"; import { toNodeHandler, fromNodeHeaders } from "better-auth/node"; import { auth } from "./auth.js"; const app = express(); const PORT = Number(process.env.AUTH_PORT ?? 4000); app.use( cors({ origin: [ "http://localhost:5173", "http://localhost:5174", "http://localhost:5175", ], credentials: true, }), ); // Mount better-auth handler FIRST — it handles /api/auth/*splat // Note: do NOT use express.json() before this handler app.all("/api/auth/*splat", toNodeHandler(auth)); // Mount json middleware only for routes below app.use(express.json()); // Token exchange endpoint: game client calls this with its session cookie // and receives a JWT suitable for SpacetimeDB app.get("/api/auth/spacetimedb-token", async (req, res) => { const session = await auth.api.getSession({ headers: fromNodeHeaders(req.headers), }); if (!session) { return res.status(401).json({ error: "Not authenticated" }); } // Get a JWT for this session const jwtResult = await auth.api.getToken({ headers: fromNodeHeaders(req.headers), }); if (!jwtResult?.token) { return res.status(500).json({ error: "Failed to generate token" }); } return res.json({ token: jwtResult.token }); }); app.listen(PORT, () => { console.log(`[auth] Auth server running on http://localhost:${PORT}`); console.log(`[auth] OIDC issuer: ${process.env.BETTER_AUTH_URL ?? `http://localhost:${PORT}`}`); });