Skip to Content
Build an appAuthentication

Authentication

What this layer solves

Most apps have pages anyone can see (public) and pages that require logging in (protected/authenticated). Authentication answers the question: “Who is this user?” Authorization answers: “What are they allowed to do?”

Public vs protected pages

TypeExampleWhat happens
PublicLanding page, pricing, blog, docsAnyone can visit — no login required
ProtectedDashboard, settings, billing, adminUser must be logged in; redirected to sign-in if not

In a Next.js app, you enforce this with middleware (checks the session before rendering) or server component logic (redirect if no user). The pattern is the same regardless of auth provider.

How authentication works (simplified)

  1. User clicks Sign in → gets sent to the auth provider (Google, GitHub, email link, etc.)
  2. Provider verifies identity → sends back a token (usually a JWT or session cookie)
  3. Your app stores that token → checks it on every protected request
  4. On Sign out, the token is destroyed

OAuth is the protocol that lets users sign in with Google, GitHub, Apple, etc. instead of creating a new password. Most auth services handle the OAuth flow for you.

Options

ServiceBest forTradeoffs
ClerkDrop-in UI components, great DX, fast setupPaid past free tier; vendor dependency
Supabase AuthAlready using Supabase for databaseTighter coupling to Supabase ecosystem
Neon AuthAlready using Neon for PostgresNewer; growing feature set
NextAuth / Auth.jsMaximum control, self-hosted session logicMore setup; you manage more of the flow
Firebase AuthGoogle ecosystem, mobile-firstDifferent data model than SQL-based stacks
Nick’s Pick

Clerk for most projects — fast to set up, beautiful pre-built components, and you can swap later if needed. If you’re already on Supabase, use Supabase Auth to keep everything in one place.

Outline: adding auth to a Next.js app (Clerk example)

  1. Install the Clerk SDK — npm install @clerk/nextjs
  2. Add env varsNEXT_PUBLIC_CLERK_PUBLISHABLE_KEY and CLERK_SECRET_KEY from your Clerk dashboard
  3. Wrap your app with <ClerkProvider> in layout.tsx
  4. Add middlewareclerkMiddleware() in middleware.ts to protect routes
  5. Public routes — explicitly list which paths skip auth (e.g. /, /pricing, /blog/*)
  6. Sign in/up pages — use Clerk’s <SignIn /> and <SignUp /> components or build custom UI
  7. Access userauth() in server components, useUser() in client components

Key concepts to understand

Session — a record that the user is currently logged in. Can be stored as a cookie, JWT, or server-side session.

JWT (JSON Web Token) — a compact, signed token containing user info. Common in modern auth; your app decodes it to know who’s making the request.

OAuth provider — Google, GitHub, Apple, etc. — they verify identity so you don’t have to handle passwords.

Row Level Security (RLS) — database-level rules that control which rows a user can read/write. Used heavily with Supabase. See Security basics.

Protected API routes — your API endpoints should also check auth, not just the frontend pages. Never trust the client alone.

When to pick an alternative

  • Auth.js if you want full control and don’t mind wiring the UI yourself.
  • Supabase Auth if your database is already Supabase and you want fewer moving parts.
  • Firebase Auth if you’re in Google’s ecosystem and using Firestore.

Last reviewed: April 2026.