import { createSupabaseAdminClient } from "@/lib/supabase/admin" import { hashApiKey } from "@/lib/api-key" import { rateLimit } from "@/lib/rate-limit" interface AuthenticatedApiUser { userIdentifier: string tier: string } export async function authenticateApiRequest( request: Request ): Promise< | { authenticated: true; user: AuthenticatedApiUser } | { authenticated: false; status: number; error: string } > { const authorizationHeader = request.headers.get("authorization") if (!authorizationHeader?.startsWith("Bearer ")) { return { authenticated: false, status: 401, error: "missing or invalid authorization header", } } const apiKey = authorizationHeader.slice(7) if (!apiKey.startsWith("asa_")) { return { authenticated: false, status: 401, error: "invalid api key format" } } const keyHash = hashApiKey(apiKey) const adminClient = createSupabaseAdminClient() const { data: keyRow } = await adminClient .from("api_keys") .select("user_id") .eq("key_hash", keyHash) .is("revoked_at", null) .single() if (!keyRow) { return { authenticated: false, status: 401, error: "invalid or revoked api key" } } const { data: userProfile } = await adminClient .from("user_profiles") .select("tier") .eq("id", keyRow.user_id) .single() if (!userProfile || userProfile.tier !== "developer") { return { authenticated: false, status: 403, error: "api access requires the developer plan", } } const rateLimitResult = await rateLimit(`api:${keyRow.user_id}`, 100, 60_000) if (!rateLimitResult.success) { return { authenticated: false, status: 429, error: `rate limit exceeded. ${rateLimitResult.remaining} requests remaining.`, } } adminClient .from("api_keys") .update({ last_used_at: new Date().toISOString() }) .eq("key_hash", keyHash) .then(({ error: updateError }) => { if (updateError) { console.error("failed to update api key last_used_at:", updateError) } }) return { authenticated: true, user: { userIdentifier: keyRow.user_id, tier: userProfile.tier }, } }