How to Add Authentication to Next.js (2026 Step-by-Step)
There's no single 'right' auth library for Next.js — the choice depends on whether you want batteries-included social login (Clerk), full flexibility with self-host (Auth.js), or maximum simplicity for a focused product (custom JWT). This guide covers all three with working examples and honest tradeoffs.
The three real options for Next.js auth
Clerk — drop-in hosted auth. Pre-built UI components (`<SignIn />`, `<UserButton />`), social login providers configured in their dashboard, generous free tier (10k MAU). Trade-off: another vendor in your stack, less control over the user table, $25/month past the free tier.
Auth.js (formerly NextAuth) — open-source auth library. Bring your own database, configure providers in code, full control. Trade-off: more setup, more concepts to learn, you maintain it. Free forever.
Custom JWT — for products with simple auth needs (email + password, one or two roles). Write a `hashPassword` + `verifyPassword` + `signJWT` + `verifyJWT` helper, set an httpOnly cookie, done. Trade-off: no social login, no magic links, you're rolling your own — including the parts you'll get wrong.
When to use each
Use Clerk if: you want auth working in 30 minutes, you need social login (Google, GitHub, Apple) without configuring OAuth apps yourself, you have non-technical teammates who'll manage user lists from a dashboard, and you don't mind a vendor.
Use Auth.js if: you want zero vendor lock-in, you need uncommon providers (specific SAML, OIDC, identity federation), you want full control over the user table and session storage, and you're comfortable with auth concepts.
Use custom JWT if: your auth is email + password only, you don't anticipate adding social login, you have a single user-types schema, and you're comfortable with the security responsibility. This is what InBuild itself uses. If you want that shape generated rather than typed, describe the app and InBuild generates a Next.js starting point with email-and-password auth and a protected dashboard — a paid plan is required to generate.
Clerk — 30 minute setup
Sign up at clerk.com → create application → copy the API keys to `.env.local` as `NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY` and `CLERK_SECRET_KEY`.
Install `npm i @clerk/nextjs`. Wrap your `app/layout.tsx` with `<ClerkProvider>`. Add `clerkMiddleware()` in `middleware.ts`. Drop `<SignIn />` and `<SignUp />` on your auth pages. Use `auth()` server-side to get the user; `<UserButton />` client-side for the avatar dropdown.
Configure social providers in Clerk's dashboard (no code). Configure email templates in the dashboard. Configure session length in the dashboard. Most of what you'd normally code lives in their UI.
Auth.js — 2 hour setup
Install `npm i next-auth@beta`. Auth.js v5 (current in 2026) supports App Router natively.
Create `auth.ts` at the project root configuring providers (e.g. GitHub: register an OAuth app on GitHub, paste client ID + secret into env vars). Export `handlers`, `auth`, `signIn`, `signOut`. Create `app/api/auth/[...nextauth]/route.ts` exporting `handlers.GET` and `handlers.POST`.
Add a Prisma adapter (or another database adapter) so users persist. Auth.js handles the OAuth dance; you handle the user table. Wrap protected pages with `auth()` server-side to check for a session.
Custom JWT — under 100 lines of code
Install `jose` (modern JWT library) and `bcryptjs` (password hashing). Write `lib/auth.ts` with: `hashPassword(plain)` returning a bcrypt hash, `verifyPassword(plain, hash)` returning boolean, `createToken({ userId, email })` returning a signed JWT, `verifyToken(token)` returning the payload or null.
Build `app/api/auth/signup/route.ts` and `app/api/auth/login/route.ts` that validate input (Zod is the standard), look up or create the user in your DB, hash the password, and on success set an httpOnly secure cookie containing the JWT. Writing the spec down first helps whether a person or an AI builder implements it — draft a structured prompt that lists the routes, roles and pages before you open the editor.
Add a middleware that reads the cookie, verifies the JWT, and either allows the request through (authenticated) or redirects to /login. Use the `next/server` `NextResponse.redirect` from middleware for unauthenticated requests.
Security essentials regardless of approach
Cookies: `httpOnly: true`, `secure: true` in production, `sameSite: 'strict'` or `'lax'`. Without these, your auth cookie is reachable by client JavaScript (XSS exposure) or sent on cross-site requests (CSRF exposure).
Passwords: bcrypt or Argon2 only — never MD5, SHA-1, or unsalted SHA-256. The whole point is to be slow enough that brute-force attacks are infeasible.
Rate limiting: limit failed-login attempts per IP and per username. Without it, attackers can credential-stuff your login endpoint freely.
Session length: long-lived refresh tokens + short-lived access tokens is the modern pattern. Keep access tokens to 15–60 minutes; refresh tokens to 7–30 days. Or: a simple sliding-window session (renewed on activity) that expires after 7 days of inactivity.
Production checklist: HTTPS everywhere, rotated secret keys (JWT_SECRET), email verification on signup, password reset flow with time-limited tokens, optional 2FA for sensitive accounts. Once it's deployed, check HTTPS, canonical and robots on the live URL — the same audit catches a login page that accidentally got indexed.
How to do it
- 1
Pick your auth approach
Clerk for fastest setup with social login. Auth.js for full control + open source. Custom JWT for simple email-and-password apps. The rest of the guide details each path.
- 2
Install dependencies
Clerk: `npm i @clerk/nextjs`. Auth.js: `npm i next-auth@beta` plus a DB adapter. Custom JWT: `npm i jose bcryptjs zod`.
- 3
Add environment variables
Clerk: NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY + CLERK_SECRET_KEY. Auth.js: AUTH_SECRET, AUTH_URL, provider client IDs/secrets. Custom: JWT_SECRET.
- 4
Build the auth pages and middleware
Add /login, /signup, and middleware.ts that protects /dashboard and /editor (or your auth-gated paths).
- 5
Wire the user table
Clerk/Auth.js: configure the DB adapter for your stack. Custom: a User model with id, email, hashed_password, name, createdAt, updatedAt.
- 6
Test the flows
Sign up, sign in, sign out, protected route access, password reset (if applicable), session expiration. Use a private browsing window to validate the unauthenticated path.
Frequently asked questions
Is Clerk overkill for a small project?
If your project will stay small and free tier is enough, Clerk is one of the easiest paths — 30 minutes from zero to working auth. The 'overkill' concern is mainly about cost at scale (past 10k monthly active users) or wanting full control over user data. For most early-stage projects, Clerk is the right speed/quality tradeoff.
Auth.js or Clerk for a SaaS?
Both work. Clerk wins on speed-to-working. Auth.js wins on no-vendor + free forever + maximum flexibility. For a SaaS where auth is a means to an end (not a feature), Clerk is usually the right call. For a SaaS where you'll heavily customize user flows (multi-tenant, complex roles, embedded identity), Auth.js gives you more room.
Can I switch later?
Yes, but it's painful — you'll need to migrate password hashes (impossible — users have to reset), session state, and any auth-specific schema. Start with the right choice for the next 12 months; switching is feasible but not casual.
Do I need 2FA?
Strongly recommended for SaaS dealing with paid accounts, sensitive data, or business-critical workflows. Clerk has 2FA built-in. Auth.js has community adapters. Custom JWT needs TOTP (via `otpauth` or similar). It's not a launch blocker for a brand-new product, but add it before you have >100 paying customers.
Free tools used in this guide
No signup — each runs in the browser or as a single server-side fetch.
Ready to build?
See a real InBuild template rendered live, with the exact exported code, before you pick a plan — no account needed.
Or skip the tutorial: describe it and InBuild generates the Next.js code for you. A paid plan is required to generate.
Build this with InBuildMore Next.js guides
How to Add Stripe to a Next.js Site (2026 Step-by-Step)
A complete walkthrough of wiring Stripe Checkout to a Next.js App Router project — products, prices, webhooks, customer portal, and the gotchas.
ReadTutorialNext.js SEO: The Complete Setup Guide (2026)
Everything you need to set up SEO correctly on a Next.js App Router site: metadata, sitemap, robots.txt, structured data, OG images, Core Web Vitals — and whether you still need next-seo.
ReadTutorialHow to Add OpenAI to Next.js (2026 Step-by-Step Guide)
A complete walkthrough of integrating OpenAI's API into a Next.js App Router site — including the AI SDK, streaming responses, rate limiting, and the gotchas with edge runtimes.
Read