Authentication That Actually Protects Your Users
Why I chose Better Auth for vibestacks, and the security concepts every SaaS founder should understand before shipping.

Authentication is the gatekeeper of every SaaS application. Get it wrong and you're exposing users to credential stuffing, session hijacking, and data breaches - which can lead to lawsuits and destroyed trust.
It's important to get it right and build on a foundation that scales from your first user to your millionth.
Authentication vs Authorization
Two terms that get confused constantly.
Authentication = "Who are you?" Proving your identity through username/password, magic links, or OAuth providers like Google and GitHub.
Authorization = "What can you do?" After you're authenticated, what actions are you permitted to take? An admin should be able to block users. A regular user shouldn't.
After evaluating Clerk, NextAuth, Better Auth, and Auth0, I chose Better Auth. Let me explain why.
In my 5 years of software engineering, I've seen companies making millions in revenue get this wrong. Even with millions of users, they're losing customers daily to attacks that Better Auth handles out of the box.
Password Storage Done Right
First thing to understand: nobody competent stores passwords in plain text. But encryption isn't the answer either.
Encryption is reversible - you encrypt data with a key, and anyone with that key can decrypt it back to the original. Pretty unsafe if a hacker gets their hands on that key.
Hashing is the current standard. It's one-way. You transform the password into a scrambled string, and there's no key to reverse it. Ever. The same input always produces the same output, but you can't work backwards.
Here's how login actually works:
- User signs up with password "MySecret123"
- Server hashes it →
a7f8d2e9b4c1...(stored in database) - User logs in, types "MySecret123"
- Server hashes what they typed →
a7f8d2e9b4c1... - Hashes match? You're in.
The password itself is never stored anywhere. Even if attackers steal your entire database, they only get hashes - not passwords.
Want to check if your password has been exposed? Check haveibeenpwned.com.
Not all hashing is equal. Old algorithms like MD5 are fast. Too fast. Attackers can try billions of guesses per second on modern GPUs.
Better Auth uses Scrypt, which is memory-hard, slow on purpose, and expensive to attack. Brute forcing becomes financially impractical.
This is the first line of defence. No product will ever be entirely safe, but multiple barriers of defence means fewer headaches.
Defence in Depth
vibestacks gives you additional security layers with minimal configuration. Here's what's included.
Rate Limiting
Safeguards against brute-force attacks. Limits applied across all routes, stricter on sensitive endpoints.
Here's a story from a big tech product I was part of: hackers figured out our rate limit threshold and adjusted their attacks to stay just below it. They didn't get blocked, but kept trying passwords slowly over time.
We lowered the limit. They adjusted. We lowered it again. They adjusted again.
Rate limiting alone wasn't enough. We needed to answer a different question: is this a human or a bot?
Cloudflare Turnstile solved it. It's a CAPTCHA alternative that verifies requests come from real humans - but without those annoying "click all the traffic lights" puzzles. It analyzes browser behavior in the background: mouse movements, timing patterns, how the page loaded. Bots can stay under rate limits, but they can't fake human behavior.
Turnstile is just a verification widget on your login form, not a proxy sitting between you and your users. If Cloudflare's API goes down (which has happened few times), you disable the check and fall back to rate limiting. You stay in control.
vibestacks comes with Turnstile ready to enable. Add your Cloudflare site key, flip the config, done.
Session Management
After you authenticate, the server needs to remember you. Think of sessions like a wristband at a concert, show your ticket once, get a wristband, move freely without showing the ticket again.
Better Auth creates a session record in your database: user ID, expiration (default 7 days), creation time, IP address, browser info. Your browser stores a session cookie pointing to that record.
Why database-backed sessions matter: with pure JWT, the session lives entirely in a browser token. If an account gets compromised, you can't immediately log them out - the token stays valid until it expires. With database sessions, delete the record and they're instantly logged out.
Cookie Security
Session cookies have security flags that Better Auth sets by default:
- HttpOnly: JavaScript cannot read it. XSS attacks can't steal sessions.
- Secure: Only transmits over HTTPS.
- SameSite=Lax: Browser won't send it with cross-site requests. Prevents CSRF.
CSRF Protection
Cross-Site Request Forgery is sneaky. You're logged into your banking app. You visit a sketchy website with hidden code that submits "Transfer $1000" to your bank. Your browser includes your session cookie automatically. Bank sees a valid session, processes the transfer.
You never clicked anything. Just visiting was enough.
Better Auth prevents this with SameSite cookies, origin validation, and Content-Type enforcement (only accepts application/json, not simple form submissions).
OAuth Security
When you click "Sign in with Google", security happens behind the scenes:
- State parameter: Random string your app generates, Google sends back, your app verifies. Prevents attackers from tricking users into linking wrong accounts.
- PKCE: Proves the app finishing the flow is the same app that started it. Critical for mobile.
Better Auth handles both automatically - stores them in your database during the flow, verifies on callback, cleans up after.
The Comparison
Here's why I chose Better Auth over the alternatives:
| Feature | Better Auth | Clerk | NextAuth | Auth0 |
|---|---|---|---|---|
| Password hashing (Scrypt) | ✅ Built-in | N/A (managed) | ✅ Configurable | N/A (managed) |
| Database sessions | ✅ Your DB | ❌ Their servers | ✅ Optional | ❌ Their servers |
| Instant session revocation | ✅ | ✅ | ⚠️ Complex | ✅ |
| CSRF protection | ✅ Multi-layer | ✅ | ⚠️ Manual | ✅ |
| Rate limiting | ✅ Built-in | ✅ | ❌ DIY | ✅ |
| Your data, your database | ✅ | ❌ | ✅ | ❌ |
| No per-user pricing | ✅ | ❌ $0.02/MAU | ✅ | ❌ |
Clerk and Auth0 handle security well - but your data lives on their servers and you pay per user forever. At 100k users, that's $2,000/month just for auth.
NextAuth gives you control but leaves gaps. Rate limiting, CSRF protection, and proper session management require additional setup.
Better Auth gives you both: enterprise security with full data ownership. Out of the box.
What vibestacks Gives You
All of this pre-configured:
- Email/password with Scrypt hashing
- OAuth (Google, GitHub, 20+ providers) with state and PKCE
- Magic links for passwordless login
- Two-factor authentication for extra security
- Rate limiting on all routes
- Cloudflare Turnstile ready to enable
- Database-backed sessions with instant revocation
- Cookie security flags set correctly
One config file. No security research required. No weeks figuring out why your OAuth flow is vulnerable.
You focus on building your product. The auth is handled.
What's Next
Coming soon to vibestacks auth:
- Organization/team management
- Role-based access control (RBAC)
- Passkey support
- Session activity logs
The goal: enterprise-grade auth without enterprise complexity. Ship secure from day one.
Questions about the setup? Hit me up at raman@vibestacks.dev or on LinkedIn.
Read more

SaaS Security: How vibestacks Blocks SQLi, XSS & CSRF
Stop vulnerabilities before they ship. See how vibestacks's stack (Drizzle, Better Auth, Zod) neutralizes SQLi, XSS, and CSRF attacks by default.

Tailwind CSS v4: What Changed and Why It's Better
No more tailwind.config.ts. Tailwind v4 moves configuration to CSS, drops JavaScript, and ships 2x faster. Here's everything that changed.

Why We Use cn() and cva() for Component Styling
String concatenation for Tailwind classes is a mess. Here's how cn() and cva() make conditional styling clean, type-safe, and maintainable.