feat(phase1c): audit sign-in / sign-out via better-auth after hook
This commit is contained in:
@@ -1,7 +1,10 @@
|
|||||||
import { betterAuth } from "better-auth";
|
import { betterAuth } from "better-auth";
|
||||||
import { prismaAdapter } from "better-auth/adapters/prisma";
|
import { prismaAdapter } from "better-auth/adapters/prisma";
|
||||||
|
import { createAuthMiddleware } from "better-auth/api";
|
||||||
import { prisma } from "./db";
|
import { prisma } from "./db";
|
||||||
|
|
||||||
|
const AUDITED_PATHS = new Set(["/sign-in/email", "/sign-out"]);
|
||||||
|
|
||||||
export const auth = betterAuth({
|
export const auth = betterAuth({
|
||||||
database: prismaAdapter(prisma, { provider: "postgresql" }),
|
database: prismaAdapter(prisma, { provider: "postgresql" }),
|
||||||
secret: process.env.BETTER_AUTH_SECRET,
|
secret: process.env.BETTER_AUTH_SECRET,
|
||||||
@@ -21,4 +24,34 @@ export const auth = betterAuth({
|
|||||||
cookiePrefix: "sp",
|
cookiePrefix: "sp",
|
||||||
useSecureCookies: process.env.NODE_ENV === "production",
|
useSecureCookies: process.env.NODE_ENV === "production",
|
||||||
},
|
},
|
||||||
|
hooks: {
|
||||||
|
after: createAuthMiddleware(async (ctx) => {
|
||||||
|
if (!AUDITED_PATHS.has(ctx.path)) return;
|
||||||
|
const status = ctx.context.returned ? 200 : 400;
|
||||||
|
const userId =
|
||||||
|
(ctx.context.returned as { user?: { id?: string } } | undefined)?.user?.id ??
|
||||||
|
ctx.context.session?.user.id ??
|
||||||
|
null;
|
||||||
|
const ip =
|
||||||
|
ctx.request?.headers.get("x-forwarded-for")?.split(",")[0]?.trim() ??
|
||||||
|
ctx.request?.headers.get("x-real-ip") ??
|
||||||
|
null;
|
||||||
|
const ua = ctx.request?.headers.get("user-agent") ?? null;
|
||||||
|
try {
|
||||||
|
await prisma.auditLog.create({
|
||||||
|
data: {
|
||||||
|
actorUserId: userId,
|
||||||
|
projectKey: "panel",
|
||||||
|
endpoint: ctx.path,
|
||||||
|
method: ctx.method ?? "POST",
|
||||||
|
responseStatus: status,
|
||||||
|
sourceIp: ip,
|
||||||
|
userAgent: ua,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} catch {
|
||||||
|
// never break auth on audit failure
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user