Synthetic Industry

Job supabase-rls-blocks-signed-in-reads · revised 11 October 2026

Fix a Supabase table that returns nothing to signed-in users, safely

On one Supabase table a signed-in test user sees and changes only their own rows, while a second user and a signed-out visitor see none of them, shown by a repeatable test.

You might be seeing

  • A table has rows in the dashboard but the app shows an empty list with no error
  • Adding or updating a row fails with a permission or policy error for a signed-in user
  • Data appears only when the protection is switched off, or when a server key is used

No passwords, keys, card details or admin invites needed to start.

What usually happened

With row-level security on, a table with no matching policy returns no rows to the browser. A policy may name the wrong role, test a column that does not match the signed-in user, run for signed-out visitors where the user identifier is empty, or cover reading but not writing. The job finds why the policies do not match the user, writes the narrowest policies that do, and proves who can and cannot see each row.

Who it’s for: A founder or product owner whose app reads from a Supabase table and gets an empty list, no error or a permission error for signed-in users after row-level security was turned on, or who is tempted to switch the protection off to make data appear.

Usually starts when: Data exists in the table and shows in the dashboard, but the app's list is empty or an insert is refused, usually just after row-level security was enabled, a policy was edited or authentication was added.

The result: For one named table, a signed-in test user reads exactly their own rows and can insert and change only their own; a second signed-in user and a signed-out request see none of the first user's rows and cannot change them. You receive the policies as a reviewable change, the test results and a note on where server-only keys must stay.

Check whether this job fits

These questions separate a missing or mismatched policy from other causes. They need no keys, data or code.

What exactly does the app get?
Is the user signed in at the moment of the call?
Can you state the access rule in one or two sentences?
Is there a non-production copy where policies can be tried?

Answer the questions to see whether this job fits.

Nothing is sent anywhere until you choose to email us.

Send an enquiry about this outcome

Checks you can run yourself

  1. Check whether protection is on and which policies exist

    In the Supabase dashboard open the table's policies page. Note whether protection is enabled, which operations each policy covers and which roles each one names. Do not change anything.

    Look for: A table with protection on and no policy, a policy that covers reading but not inserting, or a policy that names a different role from the one your signed-in users have.

What you get

  • A migration or SQL change with comments, delivered as a pull request
  • The two-user test and its recorded results
  • A short note explaining each policy in plain words and which key belongs where
  • Reversal steps and any limits found

Included

  • One named table (and at most one directly related table) in one Supabase project, with its policies for reading, inserting, updating and deleting as agreed
  • Explain why the current policies and role grants return nothing or refuse writes for the test user
  • Write the narrowest policies that fit the agreed access rule, such as each user reaching only their own rows, naming the signed-in role explicitly
  • Check how the app calls the data: that browser code uses the browser-safe key and that a server-only key is not in browser code
  • Write a repeatable test with two test users and a signed-out request, covering reading, inserting, updating and deleting
  • Apply the change as a migration file that you review and run yourself

Not included

  • A security audit or penetration test of your whole project
  • Redesigning your data model, tenancy or roles beyond the one agreed access rule
  • Migrating or repairing existing rows, or fixing data that was exposed in the past
  • Authentication provider set-up, billing or email configuration
  • Anything that needs the live project's keys: you run the migration yourself
  • Production deployment, which stays with your team

How we know it’s done

Agreed with you before work starts. Each check produces evidence you keep.

  1. On the non-production copy, test user A reads exactly the rows owned by A, and the count matches the synthetic data.

    Evidence: The test output with the expected and actual row counts for A.

  2. Test user B and a signed-out request read none of A's rows, and attempts by B to insert a row owned by A, or to update or delete A's rows, change nothing and are refused.

    Evidence: The test output for each attempt with the status and affected row count.

  3. User A can insert a row owned by A, update it and delete it, and cannot insert a row owned by someone else.

    Evidence: The test output for each operation and the refusal.

  4. No server-only key appears in browser code, the diff contains no secret and the migration has a working reversal on the copy.

    Evidence: The key-placement check, a secret scan of the diff and the reversal run.

Sign-off. You or your authorised maintainer review the policies and the test results, run the migration on your own project and repeat one test, sign off in writing and merge. Payment follows sign-off.

If it fails. If the two-user test does not pass on the copy, you do not pay for this fixed scope. If the access rule is more complex than agreed or live exposure is suspected, we explain what we found and stop. Wider work needs a new written agreement.

When it fits, and when we stop

It fits when

  • The app uses Supabase's data interface and signed-in users through Supabase authentication
  • The access rule can be stated in one or two sentences (for example, each user reaches only rows where a column equals their identifier)
  • A non-production project or a local copy exists where the policies can be tried with test users and synthetic rows
  • An authorised maintainer on your side reviews and runs the migration

We stop and tell you if

  • The rule depends on complicated sharing, teams or roles that cannot be stated in a sentence or two, so a larger design job is needed
  • The only way to reproduce the problem is with live customer data or live keys
  • The table was exposed publicly and may have been read by others: that needs an incident response before any repair
  • The cause is an outage or a billing problem with the Supabase project itself

What could go wrong

Before you run it, nothing changes. After the migration, a down-migration that restores the previous policy definitions is provided, which your maintainer can run. Reversal restores the earlier behaviour, including an empty list, so it is a recovery step and not a fix.

Scroll the table sideways to read it all.

RiskHow we handle it
A policy that is too wide exposes other users' rows.The acceptance test tries to read and change another user's row and read as a signed-out visitor, and every attempt must fail.
A server-only key in browser code bypasses every policy.We check where each key is used and tell you to rotate any key found in browser code, which only you can do.
A migration run against the live project locks or exposes data.The migration is tried on a non-production copy first, is reviewed by you and is run by you, with the reversal steps ready.

An independent reviewer tries to read, change and delete another user's row and to read as a signed-out visitor, and checks that no server-only key is in browser code. Your maintainer reviews and runs the migration. This is not a security audit.

What you can check

This is a new service. We have not delivered this job for a client yet.

Other ways to get this done

  • Supabase's own guide to row-level security explains policies, the signed-in role and why a table with protection on and no policy returns nothing. Your developer can follow it for a simple table. supabase.com
  • PostgreSQL's documentation explains default-deny behaviour and the difference between the rules for existing and new rows. www.postgresql.org

Questions

Can I just turn row-level security off?

Not safely. Without it, anyone holding your browser-side key can read and change every row the key reaches. The job exists to make the rules work, not to remove them.

Do you need my service key?

No, and it should never be in browser code. We work from an exported schema on a non-production copy.

What if my rule involves teams?

A team or role rule needs a membership model and more careful policies. We would quote that as a larger job.

Is this a security audit?

No. It fixes one table against one agreed rule and proves who can and cannot see its rows. It gives no assurance about the rest of your project.

Send an enquiry

Send us

  • The table name, the column that identifies the owner of each row and the access rule you want, in plain words
  • What the app sees (empty list, error text) and whether the user is signed in at that point
  • Whether a non-production project or local copy exists
  • Do not send keys, connection strings, real rows, source code or an access invitation in the first enquiry

Later, once you agree

  • The schema and policy definitions for the agreed table, exported without data, through an agreed company-controlled route
  • The app code that reads and writes the table, through the same route, with no keys
  • A non-production project or local copy with two test users, set up by you or with your written approval
  • The name of the person who reviews and runs the migration

You own the Supabase project, its keys and its data. We work from an exported schema and a non-production copy with synthetic rows and test users, through a company-controlled identity, never a personal login. We never hold your live keys. You run the migration on the live project.

A public HTTPS link only, without login details, query strings or fragments. No code or logs.

Sending emails your enquiry and contact address to our team through our mail provider (Resend). It is not kept in a website database. Do not send passwords, keys, recovery links, confidential code or customer records. Your contact email is unverified; nothing is ordered, charged or reserved. Privacy notice.

Email fallback: open your mail app

If website submission is unavailable, review and send the fallback email yourself. An email fallback is not a website receipt. Or write to hello@syntheticindustry.ai with “supabase-rls-blocks-signed-in-reads” as the subject.