Firebase wouldn't let me run a simple SELECT COUNT(*)
on my own fucking users. Auth0 wanted $200/month just to export user data for a board meeting. AWS Cognito's documentation made me want to quit programming.
Supabase stores users in a regular PostgreSQL table (auth.users
) that you can actually query. Want to know how many users signed up last week? SELECT COUNT(*) FROM auth.users WHERE created_at > now() - interval '7 days'
. Done.
The genius move: put auth in PostgreSQL where you can actually debug it. Row Level Security enforces permissions at the database level - hack the API, bypass the middleware, connect directly to the database, and the security policies still apply.
Your Users Live in PostgreSQL
Every user lands in auth.users
- a regular PostgreSQL table you can query, backup, and export like any other data. No special APIs, no vendor-specific formats.
This saved my ass when a client demanded user analytics with 2 hours notice. Instead of figuring out Auth0's export API, I wrote SELECT DATE(created_at), COUNT(*) FROM auth.users GROUP BY DATE(created_at)
and had charts in 10 minutes.
-- Your actual users table in PostgreSQL
SELECT id, email, created_at, last_sign_in_at
FROM auth.users
WHERE created_at > now() - interval '7 days';
-- Join users with your application data
SELECT u.email, p.company_name
FROM auth.users u
JOIN profiles p ON u.id = p.user_id
WHERE p.subscription_status = 'active';
I moved off Auth0 when they hit us with a $400/month bill for 15K users. The last straw was when exporting user data for GDPR compliance required upgrading to their "enterprise" tier. Fuck that. With Supabase, user export is COPY auth.users TO '/tmp/users.csv' CSV HEADER
.
JWT Tokens You Can Actually Use
Supabase gives you standard JWT tokens, not some bullshit proprietary format. You can decode them with any JWT library, verify them anywhere, and they contain exactly what you expect:
{
"aud": "authenticated",
"exp": 1734567890,
"iat": 1734564290,
"iss": "https://your-project.supabase.co/auth/v1",
"sub": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"email": "user@example.com",
"role": "authenticated",
"session_id": "session-uuid"
}
The tokens are signed with RSA keys (private/public pair), so no shared secrets to leak. They expire in 1 hour and refresh automatically. Unlike Auth0 tokens that are stuffed with random metadata you didn't ask for, Supabase tokens are clean.
Row Level Security (The Reason You Should Care)
This is where Supabase Auth gets scary good. PostgreSQL can read the user ID directly from your JWT token and enforce permissions at the database level. Bypass your API, write raw SQL, hack the frontend - doesn't matter. The database policies still apply.
-- Users can only see their own data
CREATE POLICY "users_own_data" ON profiles
FOR ALL USING (auth.uid() = user_id);
-- Team members can see team data
CREATE POLICY "team_access" ON projects
FOR ALL USING (
EXISTS (
SELECT 1 FROM team_members
WHERE user_id = auth.uid()
AND team_id = projects.team_id
)
);
I've seen apps where a missing WHERE user_id = current_user
in one endpoint leaked all user data. With RLS, that bug is impossible. The database enforces the rules regardless of how you access the data.
Watched a competitor spend 6 months building role-based permissions in their Node.js app. One forgotten authorization check in a GraphQL resolver exposed admin data. Their entire user base got compromised. RLS would have prevented that.
OAuth That Actually Works
OAuth setup usually means spending a weekend reading documentation and debugging redirect URLs. Supabase supports 20+ providers (Google, GitHub, Apple, Discord, etc.) and the setup is actually straightforward:
- Enable the provider in your Supabase dashboard
- Add your OAuth credentials from the provider
- Configure redirect URLs (one line of code)
- Call the sign-in method in your app
// Social login in 3 lines
const { data, error } = await supabase.auth.signInWithOAuth({
provider: 'google',
options: { redirectTo: 'https://yourapp.com/dashboard' }
});
The key thing: social login users end up in the same auth.users
table as email users. Same JWT format, same permissions, same everything. No special cases to handle.
Features That Don't Cost Extra
Stuff that costs $500+/month with Auth0 comes free with Supabase:
- Multi-Factor Authentication: TOTP, SMS, and authenticator apps
- Single Sign-On (SSO): SAML 2.0 for enterprise customers
- Phone Authentication: SMS-based login with Twilio, MessageBird, or Vonage
- Magic Links: Passwordless email authentication
- Anonymous Sign-in: Guest users that can convert to full accounts
- Web3 Authentication: Sign in with Solana wallets
This shit is included in the $25/month Pro plan. Auth0 charges $1,500+/month for the same features. The only extra cost is SMS for MFA at $0.05 per message, but TOTP apps are free and more secure anyway.
What You Actually Pay (September 2025 Pricing)
Based on current Supabase pricing:
Free Tier:
- 50,000 Monthly Active Users (MAU)
- All authentication methods included
- Perfect for MVPs and small projects
Pro Tier ($25/month):
- 100,000 MAU (then $0.00325 per additional MAU)
- Everything in free tier
- MFA, SSO, custom SMTP
- 99.9% uptime SLA
Enterprise (Custom pricing):
- Unlimited MAU with volume discounts
- Advanced audit logs
- Priority support and SLA
- Custom contracts and compliance
Real numbers: 25K active users costs $0 with Supabase, $175 with Auth0, $137 with AWS Cognito. At 100K users, Supabase costs $25/month while Auth0 hits $700+. The math gets stupid fast.
When Supabase Auth Makes Sense (And When It Doesn't)
Choose Supabase Auth when:
- You're already using PostgreSQL (or planning to)
- You want authentication that integrates with your database
- Cost matters and you don't want to pay enterprise prices for standard features
- You need the flexibility of SQL and open source
- Row Level Security appeals to you (it should)
Look elsewhere when:
- You're deep in a different ecosystem (Firebase, AWS, etc.) and integration matters more than features
- You need identity federation across hundreds of enterprise systems
- You're building a multi-tenant SaaS with complex B2B requirements (though RLS handles most of this)
- You absolutely cannot use PostgreSQL for some reason
Bottom line: if you're using PostgreSQL, Supabase Auth is a no-brainer. If you're deep in the AWS ecosystem with DynamoDB, stick with Cognito. If you're using Firebase, the migration pain might not be worth it unless Auth0's pricing is killing you.
Auth doesn't have to suck or cost a fortune. Supabase proves you can have decent security, reasonable prices, and APIs that don't make you want to throw your laptop out the window.