Mel
Mel

Reputation: 2715

Supabase RLS policy with authenticated users

I'm trying to figure out how to incorporate RLS into a supabase app that uses clerk authentication.

I i make the RLS policy (public) and

alter policy "allow create"


on "public"."events"


to public


with check (


  true

);

then i can post to supabase.

If i change public to authenticated, then I get an error saying:

Event Creation Error: { code: '42501', details: null, hint: null, message: 'new row violates row-level security policy for table "events"' }

I really want to make it true if authenticated and host_id = auth.uid().

If I try that I get the same error as posted above.

I have a users table (that holds a clerk_id and a user.id). I have an events table that holds a host_id. This is a uuid and is a foreign key to users.id.

I can see that the local host knows im authenticated and knows my user.id, because if I use the RLS policy that is true for public (the first alternative), then I can post an event and my server action (next/app router) correctly uses the user.id to make the host id.

'use server';

import { createSupabaseServerClient } from '../../lib/supabase/supabaseServerClient';
import { revalidatePath } from 'next/cache';
import { Database } from '../../lib/supabase/types/supabase';


async function getSupabaseUserId(clerkUserId: string) {
    const supabase = await createSupabaseServerClient();
    const { data, error } = await supabase
      .from('users')
      .select('id, clerk_id')
      .eq('clerk_id', clerkUserId)
      .single();
    
    console.log('Debug Information:', {
        clerkUserId,
        supabaseUserId: data?.id,
        clerkIdFromDatabase: data?.clerk_id
    });
    
    if (error) {
      console.error('Error fetching Supabase user:', error);
      return null;
    }
  
    return data?.id;
}


  
export async function createEvent(eventData: Omit<Database['public']['Tables']['events']['Insert'], 'host_id'>, clerkUserId: string) {
    try {
      const supabaseUserId = await getSupabaseUserId(clerkUserId);
      if (!supabaseUserId) {
        throw new Error('Supabase user not found');
      }
      console.log('Verification Details:', {
        clerkUserId,
        supabaseUserId,
        eventDataWithHostId: { 
          ...eventData, 
          host_id: supabaseUserId 
        }
      });
      const supabase = await createSupabaseServerClient();
      const { data, error } = await supabase
        .from('events')
        .insert({ ...eventData, host_id: supabaseUserId })
        .select()
        .single();
  
      if (error) throw error;
  
      revalidatePath('/events');
      return { success: true, event: data };
    } catch (error) {
      console.error('Event Creation Error:', error);
      return { 
        success: false, 
        error: error instanceof Error ? error.message : JSON.stringify(error) 
      };
    }
  }

How can i make my RLS policy restricted to allowing inserts if host_id = auth.uid()?

Is the problem something to do with the point that the host_id has not been created at the time the RLS policy is checking to see if the server action is permitted? I mean that if the action is permitted and the event is created, then the host_id will be the currently authenticated user's user.id, but maybe supabse can't check that until the action has run?

That doesn't seem to make sense given I cant even set the RLS policy to be the second option above (changing default public to authenticated and still just using true).

Upvotes: 0

Views: 90

Answers (0)

Related Questions