auth-helpers - can't get RLS to work from Sveltekit endpoint

I'm having a problem with the RLS for my sveltekit app from the node endpoints It works perfectly with client-side JS, but fails when I use the new auth-helpers approach from the endpoints I'm following the sveltekit-magic-link example My query looks like this
export const POST = async ({ request, locals }: RequestEvent) =>
withApiAuth({ user: locals.user }, async () => {
const data = await request.formData();
const title = data.get('title') as string;
supabaseServerClient(request).from('projects').insert([{ title }]);
return {
body: { user: locals.user }
};
});
export const POST = async ({ request, locals }: RequestEvent) =>
withApiAuth({ user: locals.user }, async () => {
const data = await request.formData();
const title = data.get('title') as string;
supabaseServerClient(request).from('projects').insert([{ title }]);
return {
body: { user: locals.user }
};
});
I get a 403 back from the endpoint with error
{
...
message: 'new row violates row-level security policy for table "projects"',
...
}
{
...
message: 'new row violates row-level security policy for table "projects"',
...
}
I print out locals.user just before the call and it is authenticated. I can't find any API documentation on the auth-helpers project, just the example in the README and the examples folder. But I'm guessing the withApiAuth({ user: locals.user }, ... ) call is setting the user from there, so don't know why my RLS isn't working there is a note in the user object
'supabase-auth-helpers-note': 'This user payload is retrieved from the cached JWT and might be stale. If you need up to date user data, please call the getUser method in a server-side context!',
'supabase-auth-helpers-note': 'This user payload is retrieved from the cached JWT and might be stale. If you need up to date user data, please call the getUser method in a server-side context!',
but none of the examples do that ... they just use locals.user. So I tried getUser ... it returns an authenticated user and all looks good, but I still get the same RLS error. Any ideas?
15 Replies
silentworks
silentworks4y ago
What does your RLS policy for this table looks like?
stukennedy
stukennedyOP4y ago
ALL for uid() = user_id it works in the superbase JS client code, just not from the auth-helper srtuff GET works, it's just anything else that doesn't
silentworks
silentworks4y ago
Do you mean if you do a insert from GET it works?
stukennedy
stukennedyOP4y ago
so I can get my products using
const sb = supabaseServerClient(request);
const { data, error, status } = await sb
.from('projects')
.select('*, groups(id)')
.order('created_at', { ascending: false });
const sb = supabaseServerClient(request);
const { data, error, status } = await sb
.from('projects')
.select('*, groups(id)')
.order('created_at', { ascending: false });
But insert fails
const sb = supabaseServerClient(request);
return sb.from('projects').insert([{ title }]);
const sb = supabaseServerClient(request);
return sb.from('projects').insert([{ title }]);
silentworks
silentworks4y ago
Try doing an insert from your GET endpoint
stukennedy
stukennedyOP4y ago
that exact same code works though if I call it from the client just using the standard supabaseClient and obvs without the request
silentworks
silentworks4y ago
I want to see if this is an issue with using it inside of a POST endpoint
stukennedy
stukennedyOP4y ago
so it's nmot my RLS oh right so put that insert in a GET I'll give it a go
silentworks
silentworks4y ago
I'm going to test it with a POST request later on today but trying to finish off some other stuff at the moment.
stukennedy
stukennedyOP4y ago
nah still fails calling it from my GET endpoint I just hijacked my page load code and used that
export const apiGetProjects = async (request: Request) => {
// const sb = supabaseServerClient(request);
// const { data, error, status } = await sb
// .from('projects')
// .select('*, groups(id)')
// .order('created_at', { ascending: false });
// if (error && status !== 406) throw error;
// return data as Project[];
const sb = supabaseServerClient(request);
const res = await sb.from('projects').insert([{ title: 'MT TEST' }]);
console.log({ res });

return [] as Project[];
};
export const apiGetProjects = async (request: Request) => {
// const sb = supabaseServerClient(request);
// const { data, error, status } = await sb
// .from('projects')
// .select('*, groups(id)')
// .order('created_at', { ascending: false });
// if (error && status !== 406) throw error;
// return data as Project[];
const sb = supabaseServerClient(request);
const res = await sb.from('projects').insert([{ title: 'MT TEST' }]);
console.log({ res });

return [] as Project[];
};
it logs out
17:16:45 [vite] page reload src/api/projects.ts (x11)
{
res: {
error: {
message: 'new row violates row-level security policy for table "projects"',
code: '42501',
details: null,
hint: null
},
data: null,
count: null,
status: 403,
statusText: 'Forbidden',
body: null
}
}
17:16:45 [vite] page reload src/api/projects.ts (x11)
{
res: {
error: {
message: 'new row violates row-level security policy for table "projects"',
code: '42501',
details: null,
hint: null
},
data: null,
count: null,
status: 403,
statusText: 'Forbidden',
body: null
}
}
stukennedy
stukennedyOP4y ago
No description
stukennedy
stukennedyOP4y ago
I looked into the code for supabaseServerClient earlier and replicated this in my code
const access_token = parseCookie(requestOrAccessToken?.headers.get('cookie'))?.['sb-access-token']
const access_token = parseCookie(requestOrAccessToken?.headers.get('cookie'))?.['sb-access-token']
It had the JWT in there and when I checked it in jwt.io it was valid .... so it does seem to be handling the auth correctly in fact if it wasn't, I'd expect a failed auth failure from supabase API and not the RLS failure it clearly gets past authentication and then maybe loses the uid() somehow NExt I'm going to try an A-B between the browser client and the endpoint client, see if I can spot a difference in the request just wondered if anyone else had hit this yet Did you get a chance to try it out?
silentworks
silentworks4y ago
Not as yet, launch week is normally quite busy Today is going to be even harder to get this tested, but I have it on my Todo list, so It's not forgotten.
stukennedy
stukennedyOP4y ago
thanks so much just discovered it was my stupid mistake .... when porting it over I was missing out passing the uid to the creating of a record which is what violated the RLS all fixed and working it's related to the fact the current API auto selects the result of an insert, which then violates the RLS. You guys mentioned this in you release video last night. But I fixed it.
silentworks
silentworks4y ago
Happy to hear you resolved this, I can remove this from my Todo list now.

Did you find this page helpful?