Closed GaryAustin1 closed 1 year ago
I can also confirm that with no user signin or local storage set... Doing supabase.auth.setAuth(access_token) With a valid user token also over rides the service key role. I suspect there maybe code on server side apps that do various things with the same supabase object and if they ever set the token for one operation, other strictly service role operations will start failing.
Service Key and no signed in user. Service Key and signed in user.
@GaryAustin1 Oh, wait. So you assume that both keys will have an effect on db authorization right? That's not the case actually, only the Authorization: Bearer <jwt>
will affect the db.
The key in apikey
is a Kong thing, it doesn't reach the db and it's only there for rejecting requests without a JWT. See this previous discussion https://github.com/supabase/supabase/discussions/1925#discussioncomment-859934.
Let me know if that clarifies things.
(Also, would have to discuss this with the infra team but it might be possible to remove the apikey
Kong protection now that postgrest has an option to disallow anon requests)
@steve-chavez I think this more a confusion thing, but it is likely users assume use of service key is absolute. As we were debugging a user issue on RLS not working with server side code involving setting token into the SB client. It came out he was using service key. All three of us assumed his code should bypass RLS. As I thought about setting token I thought it might be the issue. After seeing auth header with bearer it is clear what is happening. But if your SB client on server is doing multiple things or has left over token, (browser client pulls token from storage even if you start new client with service key). Not sure how all the server auth helpers are working. Silentworks and I thought worth reporting and at a min documenting that if your token gets set in client you lose service key from init.
Perhaps this one requires a docs update. Even if we switched it to the opposite, there would still be confusion for developers, but also with the downside that their false-assumption has caused a data-breach (RLS is bypassed).
Once a user is signed in with a client, we definitely want to adhere to the RLS of that user. Let's update the docs to make this clear?
If you run in to this, use a bogus cookie name for the service role client so it won't grab on to the user session:
cookieOptions: {
name: 'no-cookie-for-you'
}
event.locals.supabaseServer = createServerClient(PUBLIC_SUPABASE_URL, SUPABASE_KEY, {
cookies: {
get: () => '',
set: (_, __, ____) => undefined,
remove: (_, __) => undefined,
},
});
this is what i do
A temporary solution I use is it to sign out right after it's likely to get a session or right before I need to bypass RLS.
await supabase.auth.signOut()
Not ideal, but it's simple workaround
If anyone is encountering the issue now and using Vercel serverless functions, try to purge the cache in Vercel. It should get rid of what ever cookie that was there overriding the service key.
Also, I added in auth properties to disable it for serverside.
const supabase = createClient(PUBLIC_SUPABASE_URL || "", SUPABASE_SERVICE_KEY || "", {
auth: {
autoRefreshToken: false,
persistSession: false,
detectSessionInUrl: false
}
});
I also use Vercel serverless functions. I had trouble with this as well and then I realized it was because I was calling supabase.auth.signUp with Confirm email disabled.
When Confirm email is disabled, supabase.auth.signUp returns a user and session. When its enabled, only the user is returned without the session.
The user session was getting cached on my backend essentially overriding the service role and making all the other service role jobs fail. I was able to resolve this by just signing out the user after signing them up.
Forewarning - This issue is compounded if you delete the user before signing them out because supabase.auth.signOut fails when a user does not exist in the auth table even though the session stays cached on server. If that happens, you'll have to somehow clear the cookies/session management your backend uses.
Setting global auth header with the service key seems to bypass any user session stuff instead of signing out users before making service requests
const client = createClient<Database>(
url, serviceKey,
{
auth: {
autoRefreshToken: false,
persistSession: false,
detectSessionInUrl: false
},
global: {
headers: {
Authorization: `Bearer ${serviceKey}`
}
}
}
);
Bug report
In looking at a user issue with SilentWorks on Discord, a strange result was happening with SvelteKit server side requests being blocked by RLS with service_key used to init the Supabase client (in this case on server).
Seems setting a user token overrides the service_key mode of createClient.
If true this could cause strange results with left over, or applied tokens to the supabase object. This is probably the way things are supposed to work, but not sure that is well understood.
To Reproduce
I don't use server side code, so the mock up test I did is simple JS. So not a normal service_role mode, BUT I believe the results will still apply to server side code based on the network requests to PostgREST.
First Run with service key and no user signin. Table returns value. Sign in user.
Run with service key and table returns []. Turn off Signin. Still returns []. Clear local storage. Table returns value.
Difference in network requests without and with user token:
Service Key and no signed in user. Note bearer token matches service key (short)
Service Key and signed in user. Note longer bearer token.
Expected behavior
I acknowledge my test is not real world as browser should not run with service role, but I believe on a server with a left over user token from session or set on purpose the same result would occur based on the network request.
At a minimum it should be made clear service_key role applied to supabase client object only works with no user token applied.
Code to reproduce:
This could be known, but 3 of us on Discord assumed service_role would always override.
Once again, I note that on the server side maybe the issue can not occur, but I suspect if the supabase object gets a user token, it overrides the service role key.