Securing Next.js + Supabase, in depth
The specific mistakes that get apps on this stack hacked — and the exact fix for each. No generic checklists.
- ·10 min read
Supabase "Auth session missing!": getUser() null in Next.js
AuthSessionMissingError: Auth session missing! means your server-side Supabase client can't read the auth cookies, so getUser() is null. Fix: @supabase/ssr and proxy.ts.
SupabaseNext.jsAuthSSRMiddleware - ·7 min read
Fix: infinite recursion detected in policy (Supabase RLS)
The infinite recursion detected in policy error means an RLS policy queries its own table. Fix it with a SECURITY DEFINER helper function.
SupabaseRLSPostgresSecurity - ·8 min read
Supabase Storage: new row violates row-level security policy
Uploading to Supabase Storage throws new row violates row-level security policy for table objects? Add an INSERT policy on storage.objects. Here's the fix.
SupabaseStorageRLSPostgresAuth - ·9 min read
AWS Cognito + Supabase RLS: setup and gotchas
AWS Cognito works with Supabase RLS via native third-party auth. Its sub is UUID-shaped so auth.uid() works, but auth.jwt()->>'sub' is the portable pattern.
SupabaseRLSCognitoAuthPostgres - ·7 min read
Fix Supabase 'invalid claim: missing sub claim' (401)
Supabase's 'invalid claim: missing sub claim' is a GoTrue Auth error, not PostgREST — you sent an API key where a user access token belonged.
SupabaseAuthJWTGoTrueRLS - ·16 min read
Supabase Oct 30 Data API change: new tables need GRANTs
Since Oct 30, 2026, new Supabase tables in public get no Data API grants and fail with 42501. How to check your project, the exact fix, and the GRANT that reopens the hole.
SupabaseData APIRLSGrantsPostgREST - ·8 min read
WorkOS + Supabase RLS: the auth.uid() trap for prefixed ids
WorkOS is natively supported by Supabase, but its user ids are strings, not UUIDs. Here is the correct text-column RLS pattern for WorkOS + Supabase.
supabaseworkosrlsauthkitpostgres - ·5 min read
How to test your Supabase RLS policies
The Supabase SQL editor bypasses RLS, so testing there proves nothing. Here's how to actually test your policies with pgTAP and the client SDK.
SupabaseRLSTestingNext.js - ·6 min read
Is it safe to expose the Supabase anon key?
Yes — the Supabase anon key is public by design, but only if RLS is enabled on every table. Here's what makes it safe, and the one thing that makes it a leak.
SupabaseRLSSecretsNext.js - ·9 min read
Supabase leaked password protection: where to enable it
It's in Authentication → Sign In / Providers → Email: turn on "Prevent use of leaked passwords" and save. Pro plan and up. Plus why it's greyed out.
SupabaseAuthPasswordsSecurity - ·6 min read
Auth0 + Supabase RLS: the setup and the gotchas
Auth0 works with Supabase RLS via third-party auth — but you must send the ID token (not the access token), add a role claim, and use auth.jwt()->>'sub'.
SupabaseRLSAuth0AuthPostgres - ·6 min read
better-auth + Supabase RLS: the secure way
better-auth isn't a Supabase third-party auth provider, so don't share your JWT secret to fake it. Here's the secure way to enforce RLS under better-auth.
SupabaseRLSbetter-authAuthPostgres - ·9 min read
Clerk + Supabase RLS: why auth.uid() is null
With Clerk auth, auth.uid() fails because Clerk IDs aren't UUIDs — use Supabase's native integration and compare auth.jwt()->>'sub' to a text column.
SupabaseRLSClerkAuthPostgres - ·6 min read
Firebase Auth + Supabase RLS: setup and gotchas
Firebase Auth works with Supabase RLS via third-party auth — add a role:authenticated custom claim, force-refresh the first token, and match auth.jwt()->>'sub'.
SupabaseRLSFirebaseAuthPostgres - ·6 min read
NextAuth + Supabase RLS Without a Shared Secret
NextAuth isn't a Supabase-trusted auth provider, so signing your own JWT is risky. Here is the secure restricted-role pattern that keeps RLS enforced.
NextAuthSupabaseRLSPostgresAuthentication