perf(auth): resolve the caller to a narrow user projection

The session lookup and the Bearer resolver loaded the whole users row on
every authenticated request, including the profile picture bytes, the
cached briefing text and every stored integration credential. Both now
select SESSION_USER_SELECT, a named allowlist of the small columns the
request path reads, and so does the owner load for a switched record.

The few routes that need a credential or a large column read it
themselves at the moment of use: the factor verifiers load the password
hash and TOTP secret, the profile response loads the insurance number,
and the snapshot read loads the cached briefing text. A structural guard
holds the lookups to the projection and keeps every Bytes and
secret-shaped column out of it.
This commit is contained in:
Marc-André Bombeck committed 2026-10-20 20:07:25 +02:00
1 parent 628f37bc62
commit 567a564913
27 files changed
+543 -138

No files matched your search

@@ -60,7 +60,10 @@ export const POST = apiHandler(
return apiError("Password required", 422);
}
const target = await prisma.user.findUnique({ where: { id } });
const target = await prisma.user.findUnique({
where: { id },
select: { locale: true, username: true },
});
if (!target) return apiError("User not found", 404);
const locale = await resolveServerLocale({
+4 -1
View File
@@ -60,7 +60,10 @@ export const PUT = apiHandler(
return returnAllZodIssues(parsed.error, 422);
}
const target = await prisma.user.findUnique({ where: { id } });
const target = await prisma.user.findUnique({
where: { id },
select: { role: true },
});
if (!target) return apiError("User not found", 404);
// Prevent removing the last admin