feat: household api token auth foundation
This commit is contained in:
@@ -0,0 +1,68 @@
|
||||
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> {
|
||||
const session = await auth();
|
||||
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;
|
||||
}
|
||||
Reference in New Issue
Block a user