[{"data":1,"prerenderedAt":288},["ShallowReactive",2],{"blog-how-to/add-authentication-nextjs":3},{"id":4,"title":5,"body":6,"category":269,"date":270,"dateModified":270,"description":271,"draft":272,"extension":273,"faq":274,"featured":272,"headerVariant":275,"image":274,"keywords":274,"meta":276,"navigation":277,"ogDescription":278,"ogTitle":274,"path":279,"readTime":274,"schemaOrg":280,"schemaType":281,"seo":282,"sitemap":283,"stem":284,"tags":285,"twitterCard":286,"__hash__":287},"blog/blog/how-to/add-authentication-nextjs.md","How to Add Secure Authentication to Next.js",{"type":7,"value":8,"toc":253},"minimark",[9,13,17,21,30,35,38,42,62,82,107,126,139,152,182,186,215,219,234],[10,11],"category-badge",{"category":12},"How-To Guide",[14,15,5],"h1",{"id":16},"how-to-add-secure-authentication-to-nextjs",[18,19,20],"p",{},"Using NextAuth.js (Auth.js) for App Router",[22,23,24,27],"tldr",{},[18,25,26],{},"TL;DR",[18,28,29],{},"Use NextAuth.js for authentication. Set NEXTAUTH_SECRET in production. Use middleware to protect routes. Always verify sessions on API routes too. Check authorization (not just authentication) before accessing resources.",[31,32,34],"h2",{"id":33},"prerequisites","Prerequisites",[18,36,37],{},"You'll need a Next.js 13+ app with App Router. This guide uses NextAuth.js v4 (also known as Auth.js).",[31,39,41],{"id":40},"step-by-step-guide","Step-by-Step Guide",[43,44,46,51],"step",{"number":45},"1",[47,48,50],"h3",{"id":49},"install-nextauthjs","Install NextAuth.js",[52,53,58],"pre",{"className":54,"code":56,"language":57},[55],"language-text","npm install next-auth\n","text",[59,60,56],"code",{"__ignoreMap":61},"",[43,63,65,69,76],{"number":64},"2",[47,66,68],{"id":67},"create-the-auth-configuration","Create the auth configuration",[18,70,71,72,75],{},"Create ",[59,73,74],{},"app/api/auth/[...nextauth]/route.ts",":",[52,77,80],{"className":78,"code":79,"language":57},[55],"import NextAuth from 'next-auth';\nimport GoogleProvider from 'next-auth/providers/google';\nimport { NextAuthOptions } from 'next-auth';\n\nexport const authOptions: NextAuthOptions = {\n  providers: [\n    GoogleProvider({\n      clientId: process.env.GOOGLE_CLIENT_ID!,\n      clientSecret: process.env.GOOGLE_CLIENT_SECRET!,\n    }),\n  ],\n  callbacks: {\n    async session({ session, token }) {\n      // Add user ID to session\n      if (session.user) {\n        session.user.id = token.sub!;\n      }\n      return session;\n    },\n  },\n};\n\nconst handler = NextAuth(authOptions);\nexport { handler as GET, handler as POST };\n",[59,81,79],{"__ignoreMap":61},[43,83,85,89,95,101],{"number":84},"3",[47,86,88],{"id":87},"set-up-environment-variables","Set up environment variables",[18,90,91,92,75],{},"Add to ",[59,93,94],{},".env.local",[52,96,99],{"className":97,"code":98,"language":57},[55],"# Generate with: openssl rand -base64 32\nNEXTAUTH_SECRET=your-super-secret-key-here\nNEXTAUTH_URL=http://localhost:3000\n\n# OAuth provider credentials\nGOOGLE_CLIENT_ID=your-client-id\nGOOGLE_CLIENT_SECRET=your-client-secret\n",[59,100,98],{"__ignoreMap":61},[102,103,104],"warning-box",{},[18,105,106],{},"Critical:\nNEXTAUTH_SECRET must be set in production. Without it, your sessions are not secure.",[43,108,110,114,120],{"number":109},"4",[47,111,113],{"id":112},"protect-routes-with-middleware","Protect routes with middleware",[18,115,71,116,119],{},[59,117,118],{},"middleware.ts"," in your project root:",[52,121,124],{"className":122,"code":123,"language":57},[55],"import { withAuth } from 'next-auth/middleware';\n\nexport default withAuth({\n  callbacks: {\n    authorized: ({ token }) => !!token,\n  },\n});\n\nexport const config = {\n  matcher: ['/dashboard/:path*', '/settings/:path*', '/api/protected/:path*'],\n};\n",[59,125,123],{"__ignoreMap":61},[43,127,129,133],{"number":128},"5",[47,130,132],{"id":131},"get-session-in-server-components","Get session in Server Components",[52,134,137],{"className":135,"code":136,"language":57},[55],"import { getServerSession } from 'next-auth';\nimport { authOptions } from '@/app/api/auth/[...nextauth]/route';\nimport { redirect } from 'next/navigation';\n\nexport default async function DashboardPage() {\n  const session = await getServerSession(authOptions);\n\n  if (!session) {\n    redirect('/api/auth/signin');\n  }\n\n  return (\n    \u003Cdiv>\n      \u003Ch1>Welcome, {session.user?.name}\u003C/h1>\n    \u003C/div>\n  );\n}\n",[59,138,136],{"__ignoreMap":61},[43,140,142,146],{"number":141},"6",[47,143,145],{"id":144},"protect-api-routes","Protect API routes",[52,147,150],{"className":148,"code":149,"language":57},[55],"import { getServerSession } from 'next-auth';\nimport { authOptions } from '@/app/api/auth/[...nextauth]/route';\nimport { NextResponse } from 'next/server';\n\nexport async function GET(request: Request) {\n  const session = await getServerSession(authOptions);\n\n  if (!session) {\n    return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });\n  }\n\n  // Now check authorization (does this user own this resource?)\n  const userId = session.user.id;\n\n  // Fetch data scoped to this user\n  const data = await db.posts.findMany({ where: { authorId: userId } });\n\n  return NextResponse.json(data);\n}\n",[59,151,149],{"__ignoreMap":61},[43,153,155,159,164,170,176],{"number":154},"7",[47,156,158],{"id":157},"add-session-provider-for-client-components","Add session provider for client components",[18,160,71,161,75],{},[59,162,163],{},"app/providers.tsx",[52,165,168],{"className":166,"code":167,"language":57},[55],"'use client';\n\nimport { SessionProvider } from 'next-auth/react';\n\nexport function Providers({ children }: { children: React.ReactNode }) {\n  return \u003CSessionProvider>{children}\u003C/SessionProvider>;\n}\n",[59,169,167],{"__ignoreMap":61},[18,171,172,173,75],{},"Wrap your app in ",[59,174,175],{},"app/layout.tsx",[52,177,180],{"className":178,"code":179,"language":57},[55],"import { Providers } from './providers';\n\nexport default function RootLayout({ children }) {\n  return (\n    \u003Chtml>\n      \u003Cbody>\n        \u003CProviders>{children}\u003C/Providers>\n      \u003C/body>\n    \u003C/html>\n  );\n}\n",[59,181,179],{"__ignoreMap":61},[31,183,185],{"id":184},"common-security-mistakes","Common Security Mistakes",[187,188,189,197,203,209],"ul",{},[190,191,192,196],"li",{},[193,194,195],"strong",{},"Missing NEXTAUTH_SECRET in production"," - Sessions won't be secure",[190,198,199,202],{},[193,200,201],{},"Only checking auth on frontend"," - API routes need auth checks too",[190,204,205,208],{},[193,206,207],{},"Forgetting authorization"," - Auth proves who you are, but you still need to check if they can access the resource",[190,210,211,214],{},[193,212,213],{},"Exposing session data"," - Don't put sensitive info in the JWT/session that goes to the client",[31,216,218],{"id":217},"testing-your-auth","Testing Your Auth",[220,221,222,225,228,231],"ol",{},[190,223,224],{},"Try accessing /dashboard without logging in - should redirect",[190,226,227],{},"Try calling API routes without a session - should return 401",[190,229,230],{},"Try accessing another user's data - should be denied",[190,232,233],{},"Check browser DevTools for exposed tokens or sensitive data",[235,236,237,243,248],"related-articles",{},[238,239],"related-card",{"description":240,"href":241,"title":242},"Step-by-step guide to adding security headers. Protect against XSS, clickjacking, and MIME sniffing with CSP, X-Frame-Op","/blog/how-to/add-security-headers","How to Add Security Headers to Your Web App",[238,244],{"description":245,"href":246,"title":247},"Comprehensive guide to API key security. Learn storage, rotation, scoping, monitoring, and incident response best practi","/blog/how-to/api-key-best-practices","API Key Security Best Practices",[238,249],{"description":250,"href":251,"title":252},"Complete guide to secure Auth0 setup. Configure applications, handle callbacks safely, validate tokens, implement author","/blog/how-to/auth0-basics","How to Set Up Auth0 Securely",{"title":61,"searchDepth":254,"depth":254,"links":255},2,[256,257,267,268],{"id":33,"depth":254,"text":34},{"id":40,"depth":254,"text":41,"children":258},[259,261,262,263,264,265,266],{"id":49,"depth":260,"text":50},3,{"id":67,"depth":260,"text":68},{"id":87,"depth":260,"text":88},{"id":112,"depth":260,"text":113},{"id":131,"depth":260,"text":132},{"id":144,"depth":260,"text":145},{"id":157,"depth":260,"text":158},{"id":184,"depth":254,"text":185},{"id":217,"depth":254,"text":218},"how-to","2026-01-08","Step-by-step guide to adding secure authentication to Next.js apps. NextAuth setup, middleware protection, session handling, and common security mistakes.",false,"md",null,"yellow",{},true,"Step-by-step guide to secure auth in Next.js with NextAuth.","/blog/how-to/add-authentication-nextjs","[object Object]","HowTo",{"title":5,"description":271},{"loc":279},"blog/how-to/add-authentication-nextjs",[],"summary_large_image","UG8i41ju85vKCFrgim1_bAH6Eer6-f4-c_ffsQORyZM",1775843918546]