2

If I try to insert a new row into the table, I get an error: "New row violates row-level security policy for table".

I have a table "user_profiles" that have a foreign key "user_id" to auth table "auth.users.id"

enter image description here

I am using "supabase.auth.onAuthStateChange" hook where I want to add new row when user logs in.

enter image description here

In policies section, I have RLS enabled, but I didn't add any policies.

enter image description here

Then, I tried to add a policy from template that only authenticated users can add a row, but it didn't change anything.

enter image description here

Then, I came across this SO question and and tried to add a policy from template that only authenticated users can select, but I am still getting the same error.

enter image description here enter image description here

I implemented authentication in chrome browser extension in background script:

supabase.ts

import { createClient } from '@supabase/supabase-js' import qs from 'qs' const supaUrl = import.meta.env.VITE_SUPABASE_URL const supaANONKey = import.meta.env.VITE_SUPABASE_ANON_KEY export const supabase = createClient(supaUrl, supaANONKey, { global: { fetch: (...args) => fetch(...args), }, }) export const extensionSupabaseLogin = async () => { const redirectUri = chrome.identity.getRedirectURL('supabase-auth') const options = { provider: 'notion', redirect_to: redirectUri, ux_mode: 'redirect', } const url = `${supaUrl}/auth/v1/authorize?${qs.stringify(options)}` const originalTab = (await chrome.tabs.query({ active: true, currentWindow: true }))[0] const authenticationTab = await chrome.tabs.create({ url: 'about:blank' }) chrome.tabs.onUpdated.addListener(function notionAuthHook(tabId, _changeInfo, tab) { if (tabId === authenticationTab.id && tab.url?.startsWith(redirectUri)) { const splitUrl = tab.url?.split('#')[1] // Prompt user to sign in again if unparsable (error) if (!splitUrl) { console.error('Unparsable sign-in URL', tab.url) return } // Parse tokens from URL const authResult = qs.parse(splitUrl) const refreshToken = authResult.refresh_token as string const accessToken = authResult.access_token as string // Prompt user to sign in again if no access_token (error) if (!refreshToken || !accessToken) { console.error('No access token or refresh token returned', authResult) return } ;(async () => { const { error } = await supabase.auth.setSession({ access_token: accessToken, refresh_token: refreshToken, }) if (error) console.error(error) })() chrome.tabs.onUpdated.removeListener(notionAuthHook) chrome.tabs.remove(tabId) if (originalTab?.id) { chrome.tabs.update(originalTab.id, { active: true }) } } }) // Send users to the sign-in flow if (authenticationTab.id) { await chrome.tabs.update(authenticationTab.id, { url: url }) } } 

background.ts

import { Client } from '@notionhq/client' import { extensionSupabaseLogin, supabase } from './supabase' chrome.runtime.onMessage.addListener((request, sender, sendResponse) => { if (request.action === 'signIn') { extensionSupabaseLogin(); } else if (request.type === 'GET_NOTION_PAGE') { const { accessToken, ...options } = request.options as GetPageNotionOptions debugger if (!notionClient) { setNotionClient(accessToken) } if (notionClient) { const response = await notionClient.pages.retrieve({ ...options }) sendResponse({ type: 'SUCCESS', data: JSON.stringify(response) }) } } }); let notionClient: Client | null = null const setNotionClient = (notionCode: string) => { notionClient = new Client({ auth: notionCode, }) } const storeNotionIdentity = async (notionIdentity: { accessToken: string; refreshToken?: string }): Promise<void> => { setNotionClient(notionIdentity.accessToken) await chrome.storage.local.set({ notionIdentity, }) } const storeNotionUser = async (user: User): Promise<void> => { await chrome.storage.local.set({ user, }) } const setupAuthListener = () => { supabase.auth.onAuthStateChange(async (event, session) => { if (event === 'SIGNED_IN' || event === 'USER_UPDATED') { //this user has just signed in or their session has been updated console.log('user is signed in :', session) if (session?.access_token && session?.refresh_token) { debugger await storeNotionIdentity({ accessToken: session.access_token, refreshToken: session.refresh_token }) } if (session?.user) { await storeNotionUser({ name: session.user.user_metadata?.name, fullName: session.user.user_metadata?.full_name, email: session.user?.email ?? session.user.user_metadata?.email, userId: session.user.id, }) } if (typeof loginTabId === 'number') { chrome.tabs.sendMessage(loginTabId, `notion login success`) } } else if (event === 'SIGNED_OUT') { //the user has just signed out or their account has been deleetd console.log('user is signed out') loginTabId = null await chrome.storage.local.remove(['notionIdentity', 'user']) } }) } setupAuthListener() 
9
  • 1
    Did you try testing your RLS policies directly in SQL? Commented Apr 26, 2023 at 13:53
  • @Mansueli I am using only Notion social login. Can I use social login in SQL? Commented Apr 26, 2023 at 14:23
  • 1
    Yes. Even if you are using OAuth, you can simulate the access as the user in PSQL. Then you'll be able to try inserting/ selecting data to check if the policies are working. Commented Apr 26, 2023 at 14:28
  • @Mansueli thanks, I checked your blog post. How can I be sure that procedures are actually stored? If I run this snippet snippet in sql editor, I get a response "Success. No rows returned". Then, I run another query: call auth.login_as_user('[email protected]'); and I got the same response: "Success. No rows returned" Commented Apr 26, 2023 at 14:43
  • 1
    Maybe I need to be more clear in the blog. But you'll need to use PSQL. You can install PSQL in macOS and Windows following these links and instructions there. for Linux (debian): sudo apt-get updatesudo apt-get install postgresql-client Then you can run this command to connect with the database: psql -U postgres -h db.<ref>.supabase.co -d postgres -p 6543 Commented Apr 26, 2023 at 14:49

2 Answers 2

1

enter image description here

For me adding auth.uid() as the default value user_id column from the suggested expressions helped

Sign up to request clarification or add additional context in comments.

Comments

0

It is recommended to create a trigger for inserting a row in the user_profiles table upon a new signup. https://supabase.com/docs/guides/auth/managing-user-data#advanced-techniques

Here is an sample:

-- inserts a row into public.profiles create function public.handle_new_user() returns trigger language plpgsql security definer set search_path = public as $$ begin insert into public. user_profiles(id) values (new.id); return new; end; $$; -- trigger the function every time a user is created create trigger on_auth_user_created after insert on auth.users for each row execute procedure public.handle_new_user(); 

1 Comment

I agree with you – it's probably better to do a trigger than to insert a row after creating a user – but OP didn't ask for a trigger. They asked for a solution that would enable them to insert into user_profiles as an authenticated user.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.