SaaS Authentication: Email, OAuth, Magic Links & More
Rule #1: Use a Service
Never build authentication from scratch.
Auth seems simple but involves: password hashing, session management, token refresh, rate limiting, brute force protection, password reset flows, email verification, OAuth complexity, security updates...
Use one of these instead:
- Supabase Auth — Free, works great with Supabase projects
- Clerk — Beautiful UI, excellent DX, more expensive
- Auth0 — Enterprise features, complex pricing
- NextAuth/Auth.js — Self-hosted, more control, more work
Auth Methods Compared
Email + Password
Pros: Users expect it, simple to understand
Cons: Password management burden, reset flows
Use when: B2B products, users have work emails
Magic Links
Pros: No passwords to remember, very secure
Cons: Slow (email delay), bad for mobile
Use when: Low-frequency use, security-conscious users
Social Login (Google, GitHub)
Pros: Fast signup, no password management
Cons: Dependency on providers, privacy concerns
Use when: Consumer products, developer tools (GitHub)
Our Recommendation
Offer Email + Password AND Google OAuth. Covers 95% of users. Add magic links later if requested.
Implementing with Supabase
Supabase Auth is the fastest way to add authentication:
1. Enable Auth Providers
In Supabase dashboard: Authentication → Providers → Enable Email and Google
2. Create Auth UI
Use @supabase/auth-ui-react for a pre-built form, or build your own.
3. Handle Sessions
Use supabase.auth.getSession() to check if user is logged in. Create a wrapper component for protected routes.
4. Row Level Security
Enable RLS on all tables. Create policies that check auth.uid() matches the user_id column.
Key code pattern:
-- RLS Policy: Users can only see their own data CREATE POLICY "Users see own data" ON your_table FOR SELECT USING (auth.uid() = user_id);
Implementing with Clerk
Clerk provides the best UX but costs more:
1. Install and Configure
Add Clerk to your Next.js app with @clerk/nextjs. Wrap your app in <ClerkProvider>.
2. Add Components
Use <SignIn />, <SignUp />, <UserButton /> components. They're beautiful out of the box.
3. Protect Routes
Use middleware or <SignedIn>/<SignedOut> components to control access.
4. Get User Data
Use useUser() hook or auth() in server components to access user data.
Clerk handles everything: emails, password reset, MFA, organization management.
Common Auth Mistakes
- Storing passwords in plain text — Always use bcrypt or argon2
- No rate limiting — Attackers will brute force your login
- Weak password requirements — Minimum 8 chars, check against common passwords
- Exposing user IDs in URLs — Use UUIDs, not sequential IDs
- Not validating on backend — Never trust frontend-only auth checks
- Session tokens that never expire — Implement token refresh
- No HTTPS — Always use HTTPS in production
Auth Checklist
- Using established auth service (not rolling your own)
- Email + password with proper validation
- At least one OAuth provider (Google recommended)
- Email verification on signup
- Secure password reset flow
- Session management with reasonable expiry
- Rate limiting on auth endpoints
- HTTPS everywhere
- RLS or equivalent backend protection