I've been using Supabase as my database, but am no...
# help
t
I've been using Supabase as my database, but am now moving auth from Auth0 over to Supabase Auth. It's been going fairly smoothly, however I've now run into a roadblock. I'm using SvelteKit and all Supabase code is server-side. When a user signs in, their access token is stored in a cookie and read in
src/hooks.ts
. The user data is correctly fetched using
supabase.auth.api.getUser(accessToken)
. The issue comes in when I try to query my
profiles
table. I query it by the user's
id
. The
profiles
table
id
column is related to the
auth.users
id
column. Everything properly matches, but the query returns nothing. This is where things start getting strange. I have a
profiles.ts
file with helper functions which is what I use to call to Supabase. If I edit this file, SvelteKit hot reloads and the function then returns data as it should. However, just reloading the page does not make it return properly. As a sanity check I made it return the entire table instead of just the correct user, and it just returns an empty array. I don't think I've ever run into an error quite like this, any help would be much appreciated.
n
Hello @The Noah! This thread has been automatically created from your message in #843999948717555735 a ``few seconds ago``. Pinging @User so that they see this as well! Want to unsubscribe from this thread? Right-click the thread in Discord (or use the ... menu) and select Leave Thread to unsubscribe from future updates. Want to change the title? Use the
/title
command! We have solved your problem? Click the button below to archive it.
g
Do you ever set the token for Supabase with const { user, error } = supabase.auth.setAuth(access_token) The database calls need the token set with this call on the server side. One possibility. The hot refresh thing is strange though.
s
This is because of the way how fetching works when using server side in Svelte Kit. It would help if you share some code here so we can get a better understanding. You can also check out my project where I solve this by redirecting twice when the user logs in in order to not have this issue. https://github.com/silentworks/waiting-list
Currently I'm working on the Svelte Kit helpers for supabase-auth-helpers which should fix this sort of issue or at least guide you into how to fix it.
c
@User @User I'm also fighting with RLS and sveltekit for several days now. For me the issue is that the policies or even just enabling RLS (which should permit any access to the table if I understand correctly?) does not seem to affect read rights. No matter with what user I log in, I can access all data. The JWT Payload has the correct user data, so I assume this has also something to do with how I fetch the data via endpoints?
s
@User if you are fetching data via the endpoint you would need to set the auth as @User has pointed out above as it won't know which user is making the request otherwise.
c
Maybe this is completely stupid (quite new to this :-)) and maybe that is the problem but I pass the fetch from the load function to the endpoint
Though as I just saw, I'm using in one place the service_role for sending out invites via email... need to check if the server just always takes this, which would explain the RLS being completely ignored, correct?
(I never use the service_role on the browser)
s
yes correct about the service_role.
c
sometimes talking about it helps already πŸ˜„
Thanks
s
No problem, we are working on improving all of these, but Svelte Kit is built differently from all the other full-stack frameworks.
c
Absolutely, great work you're doing on supabase! And it was indeed the issue πŸ™‚
t
Copy code
ts
// hooks.ts
if (cookies["access-token"]) {
  const {user} = await db.supabase.auth.api.getUser(cookies["access-token"]);
  if (user) {
    event.locals.supabaseUser = user;
    console.log("user id:", user.id);
    const profile = await db.profiles.get({id: user.id});
    console.log("profile:", profile);
    event.locals.user = profile;
  }
}
Copy code
ts
// db/profiles.ts
export async function get(query: Record<string, unknown>): Promise<db.IProfile> {
  const {data, error} = await db.supabase
    .from("profiles")
    .select("*, links (id, url, name)")
    .match(query)
    .single();

  if (error) {
    console.error("DB get error [profiles]", query, error);
    return undefined;
  }

  return data;
}
s
Is that your hook in its entirety?
t
Yeah.
Copy code
ts
export async function handle({event, resolve}: {event: RequestEvent; resolve: any}) {
  const cookies = cookie.parse(event.request.headers.get("cookie") || "");

  if (cookies["access-token"]) {
    const {user} = await db.supabase.auth.api.getUser(cookies["access-token"]);

    if (user) {
      event.locals.supabaseUser = user;
      console.log("user id:", user.id);
      const profile = await db.profiles.get({id: user.id});
      console.log("profile:", profile);
      event.locals.user = profile;
    }
  }

  return await resolve(event);
}
s
You would need to have code in there to set the auth for the calls from your endpoint. Take a look at my hook here https://github.com/silentworks/waiting-list/blob/main/src/lib/handleAuth.js#L15-L18
t
Oh I see, let me try that.
Still doesn't seem to work.
s
Please share your updated code
t
Copy code
ts
export async function handle({event, resolve}: {event: RequestEvent; resolve: any}) {
  const cookies = cookie.parse(event.request.headers.get("cookie") || "");

  if (cookies["access-token"]) {
    const {user} = await db.supabase.auth.api.getUser(cookies["access-token"]);

    if (user) {
      event.locals.supabaseUser = user;
      console.log("user id:", user.id);
      const profile = await db.profiles.get({id: user.id});
      console.log("profile:", profile);
      event.locals.user = profile;

      db.supabase.auth.setAuth(cookies["access-token"]);
    }
  }

  return await resolve(event);
}
OH wait I need to put it before sorry πŸ˜…
Copy code
ts
export async function handle({event, resolve}: {event: RequestEvent; resolve: any}) {
  const cookies = cookie.parse(event.request.headers.get("cookie") || "");

  if (cookies["access-token"]) {
    const {user} = await db.supabase.auth.api.getUser(cookies["access-token"]);

    if (user) {
      db.supabase.auth.setAuth(cookies["access-token"]);

      event.locals.supabaseUser = user;
      console.log("user id:", user.id);
      const profile = await db.profiles.get({id: user.id});
      console.log("profile:", profile);
      event.locals.user = profile;
    }
  }

  return await resolve(event);
}
Here we go. This still doesn't work though.
s
Wait which part isn't working?
t
db.profiles.get
doesn't return the user.
s
Also move
db.supabase.auth.setAuth
outside of the
if (user)
Next do you have a RLS rule set for the profiles table?
t
Yeah I have RLS enabled. But the issue is that the the query doesn't work, unless I edit
profiles.ts
which causes it to hot-reload then it works just fine so idk why it's doing that.
s
Disable the RLS on that table and try it
t
That fixed it! Interesting.
s
That's not the fix though, just wanted to see if that was causing the issue
I faced this issue before
Can I see your RLS policy please?
t
It's empty, I'm just using the service role key to bypass it since all my Supabase code is server-side.
s
Oh wait, but I thought this part was running client side
t
Hooks don't.
s
yes correct and if you are using the service_role then you shouldn't be having RLS issues
t
But for some reason I am πŸ€”
s
You also don't need the piece of code I provided if you are doing everything server side
Turn RLS back on as you don't want your tables to be open
Can you please check again and confirm you are definitely using the
service_role
with the
db.supabase
object?
t
Yeah I've double checked.
g
I'd try and console.log db.supabase object at various points and see if service role key is set right before your select call at this point.
t
Yeah, I'll work on tracing it down.
Calling
db.supabase.auth.setAuth(config.supabase.key)
after
const {user} = await db.supabase.auth.api.getUser(cookies["access-token"])
seems to have fixed the issue. For some reason
getUser
was changing which JWT Supabase used for future requests.
s
db.supabase.auth.setAuth
does that not
db.supabase.auth.api.getUser
But these shouldn't make a difference since you are using the service key and just requesting for a specific
user.id
from the profiles table.
t
Well, setting the JWT after
getUser
fixes it πŸ€·β€β™‚οΈ
s
Happy to hear, I will try and create a test project later on with the scenario you have to see if I get the same results
t
πŸ‘
I did briefly look through the code of
getUser
and I didn't see any variable assignments which is quite odd.
No clue what's causing it, just have a workaround for now.
g
Hey we may have a problem....
s
@User you experiencing this issue too?
g
I turned on Service Role key with a signed in user... RLS on no policy
Testing
No go
stopped singin No go... cleared local storage. Go
s
You got a test project repo that I can clone?
g
This is straight Js
s
Not node?
g
It acted like service role with bearer header blocks
s
Because if I remember correctly the code won't work if you try the
service_role
in the browser
g
Works fine without bearer
If I wipe the cache
local storage
I wonder if on server if you send both service role and bearer token is an issue
s
Open an issue in the issue tracker and we will look into it
Probably
g
I'll test a bit more as I was doing quickly thinking of what postgrest might do if it had the authorization header of user...
s
Ok thanks @User, I think while trying to figure out this issue I have found a solution to one of my blocker's for the supabase-auth-helpers sveltekit code
g
Definitely the case, writing it up now. I believe if for any reason the supabase object has a user token applied, service role key is ignored as far as RLS goes.
https://github.com/supabase/supabase/issues/6277 I feel bad not verifying on server side code, but I'd have to set up a new test platform...
I just checked supabase.auth.setAuth(access_token) and if you do that at any point then service_role will no longer apply.
I'm really not sure this is so much a bug, as something that needs to be considered server side when using user tokens on the same supabase object as the one for service role.
t
I just need to verify the user token is valid and get the data from it, is there a different function I should be using?
g
Ha you think we know at this point? If you don't use service role in the call, provide a valid user token AND have RLS set to a real test that can be true for uid() I would think so.
If you want your server side to only do valid database calls for the user, you would normally use anon_key in that function, set the token as you did and then you should meet the RLS if it meets the policy. Here you had no policy so it did not work. If you changed the policy id=auth.uid() it probably would have worked even with the service key. The issue I generated, may or may not mean anything in the bigger scheme of things as I'm not sure people know setting a user token overrides the service key. You sort of accidentally stumbled into that by not having a policy with RLS on.
t
Okay thank you.
o
Hi You missed the channel to ask help, this thread is not related to your error πŸ˜… @User
Move your issue in #843999948717555735 so we can help you easily
c
@User oops πŸ˜„ thanks for the hint, moved it!
s
I’m going to run this by the team to see if it’s expected behaviour and if it is we will get it documented.