From 90dfa2e9cd62b94f5630ae44b521002d85a5ddc9 Mon Sep 17 00:00:00 2001 From: Dotta Date: Mon, 2 Mar 2026 17:02:01 -0600 Subject: [PATCH] feat(auth): add get-session endpoint and harden session resolution Add /api/auth/get-session for board actors to retrieve their session info. Wrap resolveSession in try/catch to prevent unhandled errors from crashing requests when auth headers are missing or malformed. Co-Authored-By: Claude Opus 4.6 --- server/src/app.ts | 17 +++++++++++++++++ server/src/middleware/auth.ts | 11 ++++++++++- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/server/src/app.ts b/server/src/app.ts index 520450c7..761087ab 100644 --- a/server/src/app.ts +++ b/server/src/app.ts @@ -66,6 +66,23 @@ export async function createApp( resolveSession: opts.resolveSession, }), ); + app.get("/api/auth/get-session", (req, res) => { + if (req.actor.type !== "board" || !req.actor.userId) { + res.status(401).json({ error: "Unauthorized" }); + return; + } + res.json({ + session: { + id: `paperclip:${req.actor.source}:${req.actor.userId}`, + userId: req.actor.userId, + }, + user: { + id: req.actor.userId, + email: null, + name: req.actor.source === "local_implicit" ? "Local Board" : null, + }, + }); + }); if (opts.betterAuthHandler) { app.all("/api/auth/*authPath", opts.betterAuthHandler); } diff --git a/server/src/middleware/auth.ts b/server/src/middleware/auth.ts index 977d5a5b..8aca256a 100644 --- a/server/src/middleware/auth.ts +++ b/server/src/middleware/auth.ts @@ -6,6 +6,7 @@ import { agentApiKeys, agents, companyMemberships, instanceUserRoles } from "@pa import { verifyLocalAgentJwt } from "../agent-auth-jwt.js"; import type { DeploymentMode } from "@paperclip/shared"; import type { BetterAuthSessionResult } from "../auth/better-auth.js"; +import { logger } from "./logger.js"; function hashToken(token: string) { return createHash("sha256").update(token).digest("hex"); @@ -28,7 +29,15 @@ export function actorMiddleware(db: Db, opts: ActorMiddlewareOptions): RequestHa const authHeader = req.header("authorization"); if (!authHeader?.toLowerCase().startsWith("bearer ")) { if (opts.deploymentMode === "authenticated" && opts.resolveSession) { - const session = await opts.resolveSession(req); + let session: BetterAuthSessionResult | null = null; + try { + session = await opts.resolveSession(req); + } catch (err) { + logger.warn( + { err, method: req.method, url: req.originalUrl }, + "Failed to resolve auth session from request headers", + ); + } if (session?.user?.id) { const userId = session.user.id; const [roleRow, memberships] = await Promise.all([