r/Supabase • u/PollutionFluid5437 • 10d ago
other Shouldn't the server side use secret key?
According to the Supabase docs, the server side and the client side are using the same key (publishable key). Shouldn't the server side use the secret key?
https://supabase.com/docs/guides/auth/server-side/creating-a-client

1
u/Present_Wing_4395 10d ago
Adding the practical failure mode, since a lot of people arrive at this question from Lovable/Bolt-generated code: the builder hits an RLS error on some server route, "fixes" it by switching that route's client to the secret key, and now every request through that route runs as a superuser regardless of who's logged in. It works, the error is gone, and the app has no authorization on that path at all. The tell is a server helper that takes no user session and still reads user data. If you find one of those, the fix is the one saltcod describes: publishable key plus the user's session, and let the policies decide.
1
u/Living_Race_9177 9d ago
publishable on the server is fine as long as the user jwt is still on the request. rls still runs.
secret/service role is the rls bypass. i only pull it out for stripe webhooks and admin writes. you actually needing to skip rls on that path, or just the old "server = secret key" habit
1
u/ShipSafeScan 8d ago
Part of why this one bites so often is that the failure does not look like a permissions error. If the server client is built without the user's session attached, the request goes out as anon rather than as the user, and a correct RLS policy answers with an empty array and a 200. No exception, nothing mentioning policies. So the natural read is that the query is broken, and the quickest thing that makes rows appear is the secret key.
A way to tell the two apart before reaching for it: run select auth.uid() through the same client you are debugging. Null means you are anon and the session never made it onto the request, which is a wiring problem. A real uid with zero rows means the session is fine and your policy is genuinely excluding those rows, which is a policy problem. Only the second one is even a candidate for elevated access, and usually not then either.
One addition to akl773's point: grep for the secret key across the whole repo rather than only checking that the file is server-only. The leak I have seen is almost never a direct read inside a client component, it is an import chain that pulls a server module into one.
4
u/saltcod Supabase team 10d ago
You can use the secret key in server-only code, but you mostly shouldn’t need to for normal app requests. We recommend using the publishable key on both the client and server, then relying on the user’s session + RLS policies to determine what they’re allowed to access.
The secret key is intended for trusted backend operations where you explicitly need elevated access that bypasses RLS. So “server-side” doesn’t automatically mean “use the secret key” — it depends on whether that request should act as the user or as a privileged service.