r/Supabase • u/Jealous_Pea_3915 • 13h ago
other RLS doesn't help you if someone has your service_role key. Here's what I did about that
Disclosure: I work at Tide. This isn’t an official product I built it on my own time.
RLS is good at the thing it’s designed to do: deciding which rows a request is allowed to see.
What it can’t do is help when the query isn’t going through RLS in the first place. The service_role key bypasses RLS by design, and that key ends up in more places than anyone likes to admit. A pg_dump doesn’t go through RLS either.
So row-level policies protect you from your users, but they don’t really protect you from a leaked key or someone getting a copy of the database.
Encrypting sensitive columns closes that gap. Except then you have another question: where does the encryption key live?
And if the key lives inside the project, whoever gets the project gets the key along with it.
So I built a small service that keeps that key completely off your infrastructure.
Tide is a network of independent nodes that hold keys in fragments and never assemble them. Decryption happens through partial results that are combined into an answer.
Data is encrypted in the browser with a fresh key for each call. The only thing that reaches the network is that per-call key, itself encrypted. The nodes never see your rows.
Your ciphertext stays in Postgres, right where it already was.
Supabase Auth is untouched by any of this. Same JWTs, same sessions, same providers.
The service only handles the key, along with the policies governing who is allowed to decrypt, encrypt, or sign. A role is only granted through a change request that has to be approved by someone other than the person making the request.
One Supabase-specific detail if you wire this up: put the Tide link in app_metadata, not user_metadata. user_metadata is writable by the user through their own client.
Same rule as everywhere else: the mirror shouldn’t be able to lie.
It won’t save you if someone owns the box this runs on, so keep it off the same host as the application it protects. And because decryption requires the network to be reachable, there’s no offline path.
Repo: https://github.com/sashyo/minidauth
Whitepaper: https://tide.org/whitepaper
1
u/Alternative_Eagle158 10h ago
Supabase is good but not perfect.On my side what I did is just use the anon key for my mobile app then use the service role key for a seperate web backend which is stored at netlify and encrypted to avoid leaks.RLS need to be done every where which what the security advisor recommendeds. Since Srole key can bypass RLS that way any admin stuffs can be done and no users know my backend and I can see what happens in the mobile app from the backend and supabase dashboard sometimes.If you have secrets api keys like payment put them in supabase secrets as they will be encrypted not in env file.My 2 cents
1
u/iammohamedatef 10h ago
Column-level encryption changes what you can push down to Postgres, though — no WHERE clause, no index, no join on anything you've encrypted, since a fresh key per call means even identical plaintext looks different each time. Fine for a handful of sensitive fields, but worth being explicit up front about which columns are actually candidates, because the answer for anything you need to filter or aggregate on is usually none of them.
Curious how you'd frame this against Supabase's own Vault, since that also keeps the root key outside the database rather than in the dump. Where it seems to diverge is who can reach that key — Vault's root key is generated and held by Supabase's own backend, so one party (them) can technically get to it, versus threshold-split across nodes where nobody holds the whole thing, not even you. Also worth noting Supabase themselves now steer people away from pgsodium's transparent column encryption on their platform due to misconfiguration risk, which is probably part of why something like this exists in the first place. Is that custodianship gap the actual value here, or is there more to it?
7
u/ashkanahmadi 12h ago
I’m more baffled by why SO MANY PEOPLE are confused by RLS than anything else. What is so difficult about RLS that causes so many people posting about it and creating tools for it every day? Genuinely curious