Introduction
Authentication is a critical part of most SaaS apps, but writing it from scratch adds risk and delays. Choose a solution that balances security, developer experience, and cost. This guide compares Clerk, Auth0, and NextAuth and offers recommendations based on your project needs.
Comparison Summary
- Clerk: Great for product-focused teams; rich UI components, magic links, and social sign-in
- Auth0: Enterprise-ready, flexible, and secure; but can be expensive for small projects
- NextAuth (Auth.js): Open-source, flexible for Next.js projects; requires more wiring but low cost
- Supabase Auth: Built-in with Supabase, free generous tier, row-level security integration
- Firebase Auth: Google-backed, massive ecosystem, free tier up to 10K users/month
- Lucia: Lightweight auth library, full control, minimal dependencies
Core Considerations
- Developer Experience (DX): How quickly can you ship auth flows?
- Pricing: Free tier limits and growth cost
- Security: MFA, session handling, passwordless, SSO
- UI: Hosted UI vs self-managed UI
- Compliance: GDPR, SOC2 (if needed)
Provider Comparison Table
| Provider | Free Tier | Paid From | MFA | SSO | Passkeys | Hosted UI | Open Source | Best For |
|---|---|---|---|---|---|---|---|---|
| Clerk | 10K MAU | 10K+ MAU | Yes (paid) | Yes (paid) | Yes | Yes | No | Fast shipping, built-in UI |
| Auth0 | 7K users | $30/mo | Yes | Yes (paid) | No | Yes | Yes | Enterprise, SSO, compliance |
| NextAuth | Unlimited | DB costs only | Via providers | Via providers | No | No | Yes | Next.js, full control |
| Supabase Auth | 50K MAU | $25/mo | Yes (preview) | No | No | Yes (basic) | Yes | Supabase ecosystem |
| Firebase Auth | 10K users | $0.02/verify | Yes | No | No | Yes | Partially | Google ecosystem |
| Lucia | Unlimited | DB costs only | Manual | Manual | No | No | Yes | Custom auth, full control |
Overview of Additional Providers
Supabase Auth integrates natively with Supabase’s PostgreSQL, providing built-in row-level security (RLS). User management and sessions are handled automatically. Best for indie hackers already using Supabase for their database.
Firebase Auth offers Google-first auth with extensive platform support (iOS, Android, Web). Free tier supports up to 10K monthly active users. Authentication methods include email/password, phone auth, and social providers. Deep Google Cloud integration enables serverless auth with Firebase Functions.
Lucia is a lightweight, unopinionated auth library for TypeScript. It provides session management, email/password auth, and OAuth. Unlike full-featured providers, you control every aspect of the auth flow. It pairs well with databases like SQLite, PostgreSQL, and MySQL. Best for developers who want minimal dependencies and complete flexibility.
Clerk: Pros & Cons
Pros:
- Prebuilt UIs for sign-in, sign-up, and profile management
- Passwordless and social login by default
- Good developer experience and SDKs for modern frameworks
Cons:
- Paid plans kick in quickly as users grow
- Less flexibility for complex enterprise flows
Best for: Indie hackers who want to ship fast with secure auth and minimal custom UI work
Auth0: Pros & Cons
Pros:
- Very flexible and powerful (SSO, MFA, enterprise features)
- Mature documentation and enterprise readiness
Cons:
- Can be expensive; pricing is complex
- Requires more configuration than Clerk
Best for: When you need enterprise authentication, SSO, or advanced compliance features
NextAuth: Pros & Cons
Pros:
- Open-source and free to use
- Tight integration with Next.js
- Flexible and extensible with adapters (e.g., Prisma)
Cons:
- You manage session security and UI
- More dev time for custom flows
Best for: Projects built with Next.js where you want full control and low cost
Implementation Patterns by Stack
Quick MVP — Clerk (Next.js)
- Install
@clerk/nextjs - Wrap your app in
<ClerkProvider> - Use
<SignedIn>and<SignedOut>components to conditionally render UI - Access user data via
useUser()hook - Protect API routes with
auth()middleware
// layout.tsx
import { ClerkProvider, SignedIn, SignedOut, UserButton } from '@clerk/nextjs'
import Link from 'next/link'
export default function RootLayout({ children }) {
return (
<ClerkProvider>
<header>
<SignedOut><Link href="/sign-in">Sign In</Link></SignedOut>
<SignedIn><UserButton afterSignOutUrl="/" /></SignedIn>
</header>
<main>{children}</main>
</ClerkProvider>
)
}
Strengths: Zero UI work. Works in 30 minutes. Includes dark mode, localization. Weaknesses: Paid tiers escalate quickly. Limited customization of auth flows.
Cost-Conscious — NextAuth with Prisma
- Install
next-authand@auth/prisma-adapter - Configure
[...nextauth].tswith providers and adapter - Create custom sign-in/sign-up pages
- Use
useSession()andgetServerSession()for session access - Manage session database with Prisma migrations
// app/api/auth/[...nextauth]/route.ts
import NextAuth from 'next-auth'
import GitHub from 'next-auth/providers/github'
import Google from 'next-auth/providers/google'
import { PrismaAdapter } from '@auth/prisma-adapter'
import { prisma } from '@/lib/prisma'
export const { handlers, signIn, signOut, auth } = NextAuth({
adapter: PrismaAdapter(prisma),
providers: [
GitHub({ clientId: process.env.GITHUB_ID!, clientSecret: process.env.GITHUB_SECRET! }),
Google({ clientId: process.env.GOOGLE_ID!, clientSecret: process.env.GOOGLE_SECRET! }),
],
pages: { signIn: '/auth/signin' },
callbacks: {
session({ session, user }) { session.user.id = user.id; return session }
}
})
Strengths: Free, full control, extensible with custom providers. Weaknesses: Requires building auth UI, managing sessions, and handling security yourself.
Enterprise-Ready — Auth0
- Create Auth0 tenant and configure connections
- Install
@auth0/nextjs-auth0SDK - Set up universal login flow
- Configure roles, permissions, and MFA in dashboard
- Integrate with enterprise SSO (SAML, OIDC, LDAP)
// app/page.tsx
import { getSession } from '@auth0/nextjs-auth0'
import Link from 'next/link'
export default async function Home() {
const session = await getSession()
return (
<nav>
{session ? (
<Link href="/api/auth/logout">Logout ({session.user.name})</Link>
) : (
<Link href="/api/auth/login">Login</Link>
)}
</nav>
)
}
Strengths: Enterprise features out of box. SOC2 compliant. Extensive documentation. Weaknesses: Pricing scales fast. Complex configuration for basic flows.
Supabase Auth (PostgreSQL-native)
- Initialize Supabase client with
@supabase/supabase-js - Use
supabase.auth.signUp()andsignIn()methods - Configure RLS policies for database security
- Use
supabase.auth.onAuthStateChange()for session management
// lib/supabase.ts
import { createClient } from '@supabase/supabase-js'
export const supabase = createClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
)
// app/page.tsx (client component)
const { data: { user } } = await supabase.auth.getUser()
if (user) {
// Query user-specific data via RLS policies
const { data } = await supabase.from('projects').select('*')
}
Strengths: Free up to 50K MAU. Tight PostgreSQL integration. RLS ensures security at database level. Weaknesses: Limited social providers. No built-in SSO. Less mature than dedicated auth providers.
Lightweight Control — Lucia
- Install
luciaand database adapter - Initialize Lucia with your database connection
- Create auth API routes for signup, login, logout
- Build custom session management
// lib/auth.ts
import { Lucia } from 'lucia'
import { PrismaAdapter } from '@lucia-auth/adapter-prisma'
import { prisma } from './prisma'
export const lucia = new Lucia(new PrismaAdapter(prisma.session, prisma.user))
export type Auth = typeof lucia
Strengths: Minimal dependencies, full control, TypeScript-first, works with any framework. Weaknesses: You build everything. No UI components. Security responsibility entirely on you.
Pricing Comparison for Indie Hackers
Pricing is often the deciding factor for bootstrapped founders. Here’s the real-world cost at different stages:
| Provider | MVP Stage (0-100 users) | Growth Stage (1K-10K users) | Scale Stage (10K+ users) |
|---|---|---|---|
| Clerk | Free | $25-50/mo | $100-500/mo+ |
| Auth0 | Free (7K users) | $30-100/mo | Enterprise pricing |
| NextAuth | Free (DB cost: $5-30/mo) | Free (DB cost: $30-100/mo) | Free (DB cost scales) |
| Supabase Auth | Free (50K MAU) | $25/mo | $100-500/mo+ |
| Firebase Auth | Free (10K users) | $0.02/verification | Custom pricing |
| Lucia | Free (DB cost: $5-30/mo) | Free (DB cost: $30-100/mo) | Free (DB cost scales) |
Cost efficiency ranking for indie hackers:
- Lucia / NextAuth — lowest cost, highest effort
- Supabase Auth — generous free tier, great value
- Clerk — reasonable for early stage, escalates
- Firebase Auth — good free tier, can get expensive at scale
- Auth0 — best value at enterprise, expensive for indie
User Management Features
Beyond authentication, user management infrastructure affects your daily operations.
Built-in user admin dashboard:
- Clerk: User management portal included. Search, filter, impersonate users. Manage sessions and roles. No build required.
- Auth0: Comprehensive dashboard for users, roles, logs, and rules. Extensive but complex.
- NextAuth: No dashboard. Build your own admin panel or use a third-party tool.
- Supabase Auth: Basic user management in Supabase dashboard. Limited but functional.
- Firebase Auth: User management in Firebase console. Basic search and disable/enable.
- Lucia: No dashboard. Full DIY approach.
User profile enrichment:
- Clerk and Auth0 support custom user metadata, organization membership, and webhook events for user lifecycle.
- Supabase and Firebase provide basic profile fields but require custom implementation for complex data.
- NextAuth and Lucia give you raw database access—build whatever profile structure you need.
MFA, SSO, and Passkeys
Authentication security requirements evolve as your product grows.
Multi-Factor Authentication (MFA)
- Clerk: MFA with TOTP (authenticator apps) and SMS. Available on paid plans.
- Auth0: Comprehensive MFA including TOTP, SMS, push notifications, and WebAuthn. Configurable risk-based MFA triggers.
- NextAuth: No built-in MFA. Implement via custom provider or third-party service (workos, descope).
- Supabase Auth: MFA in preview (TOTP). Actively being developed.
- Firebase Auth: MFA with TOTP and SMS. Native SDK support.
- Lucia: No built-in MFA. Implement from scratch or integrate an MFA library.
Single Sign-On (SSO)
SSO enables enterprise customers to use their corporate identity providers (Okta, Azure AD, Google Workspace).
- Auth0 and Clerk: Enterprise SSO through SAML/OIDC. Auth0 has deeper support for complex enterprise configurations.
- NextAuth: SSO via generic OAuth/OIDC provider. Works with any standard-compliant IDP but requires configuration.
- Supabase Auth and Firebase Auth: Limited or no enterprise SSO. Not suitable for B2B enterprise products.
- Lucia: No SSO. Build your own OIDC integration.
Passkeys
Passkeys (WebAuthn) are the emerging standard for passwordless authentication. They replace passwords with biometric authentication on user devices.
- Clerk: Built-in passkey support on paid plans. Simple toggle in dashboard.
- Auth0: Passkey support in preview. Available through custom actions.
- NextAuth: No native passkey support. Implement via WebAuthn library (
@simplewebauthn/server). - Supabase Auth: Passkeys not yet supported. Rely on passwordless email links instead.
- Firebase Auth: Passkey support through Google Identity Services.
- Lucia: No passkey support. DIY with WebAuthn libraries.
Migration Between Providers
Migrating auth providers is painful but sometimes necessary as requirements change. Plan migration strategy upfront.
Common Migration Patterns
From host-based (Clerk, Auth0) to NextAuth/Lucia:
- Export user data (email, hashed passwords, metadata) from the provider’s dashboard or API.
- Import users into your new database with hashed passwords preserved (if using same algorithm).
- Force password reset for all migrated users on first login.
- Run both auth systems in parallel during transition, using feature flags to migrate users gradually.
Database migration considerations:
- User IDs must remain consistent to preserve data relationships.
- Session tokens will be invalidated. All users must re-login after migration.
- Notify users about the migration 2 weeks in advance.
- Plan for 1-2 days of full-stack testing before cutover.
Migration Cost-Benefit
| Migrate To | Migration Difficulty | Benefit |
|---|---|---|
| Clerk from anything | Medium | Better DX, features |
| Auth0 from anything | Medium-High | Enterprise features, SSO |
| NextAuth from anything | Medium | Lower cost, full control |
| Supabase from Firebase | Medium | Lower cost, PostgreSQL RLS |
| Lucia from anything | High | Maximum flexibility, zero vendor lock-in |
Security Considerations
Authentication security mistakes are the most common vulnerability in indie products.
Session Security
- Use JWTs with short expiration (15-60 minutes) and refresh tokens for extending sessions.
- Store tokens in httpOnly cookies, not localStorage (which is vulnerable to XSS).
- Implement CSRF protection for all auth-related endpoints.
- Rotate session IDs after login to prevent session fixation attacks.
- Set session timeouts: inactive sessions expire after 7 days, absolute maximum 30 days.
Password Policies
- Minimum 8 characters, no maximum.
- Ban common passwords (use a library like
zxcvbnto check password strength). - Hash passwords with bcrypt (cost factor 12+) or Argon2id.
- Never store plaintext passwords. Never transmit passwords over unencrypted connections.
- Implement rate limiting: 5 failed login attempts triggers a 15-minute lockout.
OAuth Security
- Validate state parameters to prevent CSRF in OAuth flows.
- Use PKCE (Proof Key for Code Exchange) for mobile and SPA OAuth flows.
- Verify the
issclaim in JWT tokens from OAuth providers. - Never log tokens or authorization codes.
API Protection
- Authenticate all API routes. Use middleware to enforce auth globally.
- Implement proper CORS policies. Don’t use
Access-Control-Allow-Origin: *for authenticated endpoints. - Use API rate limiting to prevent brute force attacks on auth endpoints.
- Log authentication events (successful logins, failed attempts, password resets) for security auditing.
Compliance Basics
- GDPR: Provide user data export and account deletion. Document data processing. Obtain consent for cookies and tracking.
- SOC2: Required for B2B enterprise deals. Auth0 and Clerk offer SOC2 reports. Self-managed solutions require external audit.
- CCPA: If serving California users, support data deletion requests and opt-out mechanisms.
Recommendations by Use Case
| Use Case | Recommended Provider | Runner Up |
|---|---|---|
| Quick MVP, need to ship today | Clerk | Supabase Auth |
| Next.js project, want full control | NextAuth (Auth.js) | Lucia |
| Enterprise B2B SaaS | Auth0 | Clerk (Enterprise plan) |
| Supabase project, PostgreSQL data | Supabase Auth | NextAuth with Prisma |
| Maximum cost savings | NextAuth | Lucia |
| Google-first ecosystem | Firebase Auth | Supabase Auth |
| Learning auth internals | Lucia | NextAuth |
Final Thoughts
Authentication is a solved problem, but each approach presents tradeoffs. For indie hackers launching an MVP, speed and developer experience often win. Start simple and iterate: use hosted solutions for early users and migrate to flexible or managed solutions when you need them.
Action: Pick your stack and implement sign-up/login this week—move quickly and test the user flow with early users. The perfect auth solution doesn’t exist. Pick the one that removes friction from your current stage and plan to evolve as you grow.
Demonstration GIFs & recording
If you plan to create a quick demo or GIF (sign-up flow, profile updates), follow /assets/gif-instructions/README.md to record a terminal or screen and convert it to a GIF. Suggested recording steps:
- Record: Start a dev server and walk through sign-up with test accounts
- Cropping: Focus on the browser window for the sign-up + redirect
- Convert: Use the scripted ffmpeg steps to produce an optimized GIF
Comments