fix: resolve infinite recursion in admin_users RLS policy

The admin_users policy was checking if user is admin by querying
the same table, causing infinite recursion. Changed to allow users
to view their own admin record directly using auth.uid() = user_id.

This fixes the error: 'infinite recursion detected in policy for
relation admin_users'
This commit is contained in:
2025-12-18 14:11:22 +01:00
parent 7d307ac253
commit e960d1bace
3 changed files with 59 additions and 5 deletions

View File

@@ -0,0 +1,48 @@
import { createServerComponentClient } from '@supabase/auth-helpers-nextjs';
import { cookies } from 'next/headers';
import { NextResponse } from 'next/server';
export async function GET() {
const supabase = createServerComponentClient({ cookies });
// Get current user
const { data: { user }, error: userError } = await supabase.auth.getUser();
if (userError || !user) {
return NextResponse.json({
success: false,
error: 'Not authenticated',
userError: userError?.message
});
}
// Check admin_users table
const { data: adminData, error: adminError } = await supabase
.from('admin_users')
.select('*')
.eq('user_id', user.id)
.single();
// Get all admin users (for debugging)
const { data: allAdmins, error: allAdminsError } = await supabase
.from('admin_users')
.select('*');
return NextResponse.json({
success: true,
currentUser: {
id: user.id,
email: user.email
},
adminCheck: {
data: adminData,
error: adminError?.message,
isAdmin: !!adminData
},
allAdmins: {
data: allAdmins,
error: allAdminsError?.message,
count: allAdmins?.length || 0
}
});
}

View File

@@ -189,6 +189,7 @@ export async function getGlobalApiStats(): Promise<ApiStats | null> {
*/ */
export async function checkIsAdmin(userId: string): Promise<boolean> { export async function checkIsAdmin(userId: string): Promise<boolean> {
try { try {
console.log('[checkIsAdmin] Checking admin status for user:', userId);
const supabase = createServerComponentClient({ cookies }); const supabase = createServerComponentClient({ cookies });
const { data, error } = await supabase const { data, error } = await supabase
@@ -197,13 +198,18 @@ export async function checkIsAdmin(userId: string): Promise<boolean> {
.eq('user_id', userId) .eq('user_id', userId)
.single(); .single();
console.log('[checkIsAdmin] Query result - data:', data, 'error:', error);
if (error) { if (error) {
console.log('[checkIsAdmin] Error occurred:', error.message);
return false; return false;
} }
return !!data; const isAdmin = !!data;
console.log('[checkIsAdmin] Final result:', isAdmin);
return isAdmin;
} catch (err) { } catch (err) {
console.error('Error checking admin status:', err); console.error('[checkIsAdmin] Exception:', err);
return false; return false;
} }
} }

View File

@@ -283,9 +283,9 @@ CREATE POLICY "Admins can view all credits" ON user_credits FOR SELECT USING (
EXISTS (SELECT 1 FROM admin_users WHERE user_id = auth.uid()) EXISTS (SELECT 1 FROM admin_users WHERE user_id = auth.uid())
); );
-- Policies for admin_users (only admins can view) -- Policies for admin_users (users can see their own admin record)
CREATE POLICY "Admins can view admin users" ON admin_users FOR SELECT USING ( CREATE POLICY "Users can view their own admin record" ON admin_users FOR SELECT USING (
EXISTS (SELECT 1 FROM admin_users WHERE user_id = auth.uid()) auth.uid() = user_id
); );
-- Note: To add robin as admin, run this after getting the user_id: -- Note: To add robin as admin, run this after getting the user_id: