diff --git a/server/src/__tests__/auth-middleware.test.ts b/server/src/__tests__/auth-middleware.test.ts new file mode 100644 index 00000000000..890d1cb8205 --- /dev/null +++ b/server/src/__tests__/auth-middleware.test.ts @@ -0,0 +1,43 @@ +import { describe, expect, it, vi } from "vitest"; +import express from "express"; +import request from "supertest"; +import { actorMiddleware } from "../middleware/auth.js"; + +function createApp(resolveSession: ReturnType) { + const app = express(); + app.use( + actorMiddleware({} as never, { + deploymentMode: "authenticated", + resolveSession, + }), + ); + app.get("/", (_req, res) => { + res.status(200).send("ok"); + }); + app.get("/api/ping", (_req, res) => { + res.status(200).json({ ok: true }); + }); + return app; +} + +describe("actorMiddleware", () => { + it("skips session resolution for non-api page requests", async () => { + const resolveSession = vi.fn(async () => null); + const app = createApp(resolveSession); + + const res = await request(app).get("/"); + + expect(res.status).toBe(200); + expect(resolveSession).not.toHaveBeenCalled(); + }); + + it("still resolves sessions for api requests", async () => { + const resolveSession = vi.fn(async () => null); + const app = createApp(resolveSession); + + const res = await request(app).get("/api/ping"); + + expect(res.status).toBe(200); + expect(resolveSession).toHaveBeenCalledOnce(); + }); +}); diff --git a/server/src/middleware/auth.ts b/server/src/middleware/auth.ts index 6140c87d5b5..5f0cef802d8 100644 --- a/server/src/middleware/auth.ts +++ b/server/src/middleware/auth.ts @@ -18,6 +18,13 @@ interface ActorMiddlewareOptions { resolveSession?: (req: Request) => Promise; } +function shouldResolveBoardSession(req: Request): boolean { + // Only API routes consume req.actor. Skipping session resolution for + // document/static requests avoids unnecessary Better Auth work on each + // Vite-served page load in authenticated dev mode. + return req.path.startsWith("/api"); +} + export function actorMiddleware(db: Db, opts: ActorMiddlewareOptions): RequestHandler { const boardAuth = boardAuthService(db); return async (req, _res, next) => { @@ -30,7 +37,11 @@ export function actorMiddleware(db: Db, opts: ActorMiddlewareOptions): RequestHa const authHeader = req.header("authorization"); if (!authHeader?.toLowerCase().startsWith("bearer ")) { - if (opts.deploymentMode === "authenticated" && opts.resolveSession) { + if ( + opts.deploymentMode === "authenticated" && + opts.resolveSession && + shouldResolveBoardSession(req) + ) { let session: BetterAuthSessionResult | null = null; try { session = await opts.resolveSession(req);