74 lines
1.9 KiB
TypeScript
74 lines
1.9 KiB
TypeScript
import { eq } from "drizzle-orm";
|
|
import { auth } from "@/lib/auth";
|
|
import { db } from "@/lib/db";
|
|
import { resolveBearerToken } from "@/modules/_core/api-token";
|
|
import { householdMembers } from "@/modules/_core/schema";
|
|
|
|
export type ApiAuthContext = {
|
|
householdId: string;
|
|
userId: string | null;
|
|
role: "owner" | "member" | null;
|
|
};
|
|
|
|
function parseBearerToken(request: Request): string | null {
|
|
const header = request.headers.get("Authorization");
|
|
if (!header?.startsWith("Bearer ")) return null;
|
|
const token = header.slice("Bearer ".length).trim();
|
|
return token.length > 0 ? token : null;
|
|
}
|
|
|
|
async function resolveSessionAuth(): Promise<ApiAuthContext | null> {
|
|
let session;
|
|
try {
|
|
session = await auth();
|
|
} catch {
|
|
return null;
|
|
}
|
|
if (!session?.user?.id) return null;
|
|
|
|
const [row] = await db
|
|
.select({
|
|
householdId: householdMembers.householdId,
|
|
role: householdMembers.role,
|
|
})
|
|
.from(householdMembers)
|
|
.where(eq(householdMembers.userId, session.user.id))
|
|
.limit(1);
|
|
|
|
if (!row) return null;
|
|
|
|
return {
|
|
householdId: row.householdId,
|
|
userId: session.user.id,
|
|
role: row.role,
|
|
};
|
|
}
|
|
|
|
export async function resolveApiAuth(request: Request): Promise<ApiAuthContext | null> {
|
|
const sessionAuth = await resolveSessionAuth();
|
|
if (sessionAuth) return sessionAuth;
|
|
|
|
const rawToken = parseBearerToken(request);
|
|
if (!rawToken) return null;
|
|
|
|
const bearer = await resolveBearerToken(rawToken);
|
|
if (!bearer) return null;
|
|
|
|
return {
|
|
householdId: bearer.householdId,
|
|
userId: null,
|
|
role: null,
|
|
};
|
|
}
|
|
|
|
export async function requireApiAuth(request: Request): Promise<ApiAuthContext> {
|
|
const ctx = await resolveApiAuth(request);
|
|
if (!ctx) {
|
|
throw new Response(JSON.stringify({ error: "Unauthorized" }), {
|
|
status: 401,
|
|
headers: { "Content-Type": "application/json" },
|
|
});
|
|
}
|
|
return ctx;
|
|
}
|