Skip to content

Commit 7c56dd1

Browse files
committed
perf(auth,api): skip getSession when no session cookie is present
Better-auth's getSession was running on every request — including API-key, public, MCP, and SDK traffic — and hitting Postgres even when no session cookie was attached. Under pool contention this manifested as a hard 5s wall: ~25% of /v1/query calls returned 500 "Failed to get session" at duration_ms=5010, the rest of the slow tail also clustered there. The /public/v1/flags/bulk endpoint showed the same pattern. Add hasSessionCookie(headers) in @databuddy/auth that checks for the better-auth session_token / session_data cookie names, and short-circuit the four hot getSession call sites: - packages/rpc/src/orpc.ts createRPCContext (covers all /rpc/*) - apps/api/src/routes/query.ts (/v1/query) - apps/api/src/middleware/website-auth.ts (/public/v1/flags/bulk and other website-scoped routes) - apps/api/src/lib/auth-wide-event.ts (per-request auth wide event)
1 parent 6f1cc45 commit 7c56dd1

5 files changed

Lines changed: 31 additions & 8 deletions

File tree

apps/api/src/lib/auth-wide-event.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import {
33
isApiKeyPresent,
44
resolveApiKey,
55
} from "@databuddy/api-keys/resolve";
6-
import { auth } from "@databuddy/auth";
6+
import { auth, hasSessionCookie } from "@databuddy/auth";
77
import { mergeWideEvent, record } from "./tracing";
88

99
export interface ResolvedAuth {
@@ -21,9 +21,12 @@ export async function applyAuthWideEvent(headers: Headers): Promise<void> {
2121
const fields: Record<string, string | number | boolean> = {};
2222

2323
const hasKey = isApiKeyPresent(headers);
24+
const sessionCookiePresent = hasSessionCookie(headers);
2425
const [session, apiKeyResult] = await record("auth", () =>
2526
Promise.all([
26-
auth.api.getSession({ headers }).catch(() => null),
27+
sessionCookiePresent
28+
? auth.api.getSession({ headers }).catch(() => null)
29+
: null,
2730
hasKey ? resolveApiKey(headers) : null,
2831
])
2932
);

apps/api/src/middleware/website-auth.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import {
33
hasWebsiteScope,
44
isApiKeyPresent,
55
} from "@databuddy/api-keys/resolve";
6-
import { auth } from "@databuddy/auth";
6+
import { auth, hasSessionCookie } from "@databuddy/auth";
77
import { db } from "@databuddy/db";
88
import { Elysia } from "elysia";
99
import { getResolvedAuth } from "../lib/auth-wide-event";
@@ -67,12 +67,15 @@ export function websiteAuth() {
6767
sessionUser = getSessionUser(session);
6868
apiKey = preResolved.apiKeyResult?.key ?? null;
6969
} else {
70+
const sessionCookiePresent = hasSessionCookie(request.headers);
7071
const [resolvedApiKey, resolvedSession] = await record(
7172
"getAuthContext",
7273
() =>
7374
Promise.all([
7475
apiKeyPresent ? getApiKeyFromHeader(request.headers) : null,
75-
auth.api.getSession({ headers: request.headers }),
76+
sessionCookiePresent
77+
? auth.api.getSession({ headers: request.headers })
78+
: null,
7679
])
7780
);
7881
session = resolvedSession;

apps/api/src/routes/query.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { auth } from "@databuddy/auth";
1+
import { auth, hasSessionCookie } from "@databuddy/auth";
22
import {
33
type ApiKeyRow,
44
getAccessibleWebsiteIds,
@@ -1057,7 +1057,9 @@ export const query = new Elysia({ prefix: "/v1/query" })
10571057
const hasApiKey = isApiKeyPresent(request.headers);
10581058
const [apiKey, session] = await Promise.all([
10591059
hasApiKey ? getApiKeyFromHeader(request.headers) : null,
1060-
auth.api.getSession({ headers: request.headers }),
1060+
hasSessionCookie(request.headers)
1061+
? auth.api.getSession({ headers: request.headers })
1062+
: null,
10611063
]);
10621064
const user = session?.user ?? null;
10631065

packages/auth/src/auth.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,19 @@ function forwardAuthLog(
217217
log.info(fields);
218218
}
219219

220+
const SESSION_COOKIE_HINTS = [
221+
"better-auth.session_token",
222+
"better-auth.session_data",
223+
];
224+
225+
export function hasSessionCookie(headers: Headers): boolean {
226+
const cookie = headers.get("cookie");
227+
if (!cookie) {
228+
return false;
229+
}
230+
return SESSION_COOKIE_HINTS.some((hint) => cookie.includes(hint));
231+
}
232+
220233
export const auth = betterAuth({
221234
logger: {
222235
log: forwardAuthLog,

packages/rpc/src/orpc.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import {
22
type ApiKeyRow,
33
getApiKeyFromHeader,
44
} from "@databuddy/api-keys/resolve";
5-
import { auth, type User } from "@databuddy/auth";
5+
import { auth, hasSessionCookie, type User } from "@databuddy/auth";
66
import { db } from "@databuddy/db";
77
import { os as createOS } from "@orpc/server";
88
import { baseErrors } from "./errors";
@@ -60,7 +60,9 @@ export const createRPCContext = async (
6060
const [session, apiKey] = preResolved
6161
? [preResolved.session, preResolved.apiKey]
6262
: await Promise.all([
63-
auth.api.getSession({ headers: opts.headers }),
63+
hasSessionCookie(opts.headers)
64+
? auth.api.getSession({ headers: opts.headers })
65+
: Promise.resolve(null),
6466
getApiKeyFromHeader(opts.headers),
6567
]);
6668

0 commit comments

Comments
 (0)