2025-04-02·9 min read

Supabase Auth deep dive — JWT, RLS, and sessions

How Supabase handles authentication under the hood, and how to configure it correctly for a production app.

SupabaseSecurity

What Supabase Auth actually is

Supabase Auth is a complete authentication system built on top of PostgreSQL. It handles user registration, login, password reset, email verification, and OAuth providers like Google and GitHub — out of the box, with no extra service needed.

Under the hood it uses JWT — JSON Web Tokens. When a user logs in, Supabase issues a signed token that proves who they are. Every request to your database includes this token, and Supabase verifies it before allowing any data access.

Row Level Security

The most important concept in Supabase is Row Level Security, or RLS. It is a PostgreSQL feature that lets you write rules directly in the database controlling who can read or write each row.

Without RLS, your API key is the only thing protecting your data. If someone gets your key, they can read everything. With RLS, even with the key, a user can only access rows the policy allows.

A simple example — a policy that lets users read only their own profile:

create policy "users can read own profile"
  on profiles for select
  using (auth.uid() = user_id);

auth.uid() returns the ID of the currently authenticated user from the JWT. The database checks this automatically on every query.

How sessions work

When a user logs in, Supabase returns two tokens — an access token that lasts one hour, and a refresh token that lasts much longer. The Supabase client library handles refreshing the access token automatically before it expires.

In a Next.js app, sessions are stored in cookies so they persist across page refreshes and server-side requests. The server can read the session and know who the user is before sending any HTML — this is what allows protected pages to redirect unauthenticated users instantly.

What EmergEdge uses this for

EmergEdge uses Supabase Auth for three things.

Newsletter subscribers. When someone enters their email, a row is created in the subscribers table. RLS ensures subscribers can only see their own record.

Admin access. The admin dashboard checks whether the logged-in user has the admin role before showing any management features. This check happens on the server, so the page never renders for unauthorised users.

Future gated content. Premium posts will check whether the reader has an active subscription before returning the full content. The check happens in the API route, not the frontend, so the content is never sent to unauthorised browsers.

The key principle

Never trust the client. All security decisions — who can read what, who has which role, whether a subscription is active — are enforced in the database with RLS policies and in server-side API routes. The frontend only displays what the server decides to give it.

Enjoyed this post? Subscribe to get new articles in your inbox.