[{"data":1,"prerenderedAt":443},["ShallowReactive",2],{"blog-how-to/protect-routes":3},{"id":4,"title":5,"body":6,"category":423,"date":424,"dateModified":425,"description":426,"draft":427,"extension":428,"faq":429,"featured":427,"headerVariant":430,"image":429,"keywords":429,"meta":431,"navigation":432,"ogDescription":433,"ogTitle":429,"path":434,"readTime":429,"schemaOrg":435,"schemaType":436,"seo":437,"sitemap":438,"stem":439,"tags":440,"twitterCard":441,"__hash__":442},"blog/blog/how-to/protect-routes.md","How to Protect Routes and API Endpoints",{"type":7,"value":8,"toc":405},"minimark",[9,13,17,21,27,32,45,54,58,73,84,88,110,126,142,155,168,184,197,210,215,241,245,278,284,288,292,295,299,302,306,309,313,316,320,327,363,386],[10,11],"category-badge",{"category":12},"How-To Guide",[14,15,5],"h1",{"id":16},"how-to-protect-routes-and-api-endpoints",[18,19,20],"p",{},"Middleware patterns, auth guards, and authorization checks",[22,23,24],"tldr",{},[18,25,26],{},"TL;DR (20 minutes):\nAlways verify authentication server-side (middleware or API route), never trust client-side auth alone. Check authorization (can this user access this resource?) not just authentication (is someone logged in?). Use middleware for route protection, but always double-check in API handlers. Return 401 for unauthenticated, 403 for unauthorized.",[28,29,31],"h2",{"id":30},"prerequisites","Prerequisites",[33,34,35,39,42],"ul",{},[36,37,38],"li",{},"An authentication system (NextAuth, Supabase Auth, Firebase Auth, etc.)",[36,40,41],{},"Basic understanding of HTTP status codes (401 vs 403)",[36,43,44],{},"A Next.js, React, or Node.js application",[46,47,48,51],"warning-box",{},[18,49,50],{},"The #1 Mistake",[18,52,53],{},"Protecting routes only on the client (hiding UI elements) does NOT secure your app. Anyone can call your API directly. Always verify authentication and authorization server-side.",[28,55,57],{"id":56},"authentication-vs-authorization","Authentication vs Authorization",[33,59,60,67],{},[36,61,62,66],{},[63,64,65],"strong",{},"Authentication (AuthN):"," Verifies WHO the user is. \"Is this person logged in?\"",[36,68,69,72],{},[63,70,71],{},"Authorization (AuthZ):"," Verifies WHAT the user can do. \"Can this user access this resource?\"",[74,75,80],"pre",{"className":76,"code":78,"language":79},[77],"language-text","// Authentication: Is someone logged in?\nif (!user) {\n  return res.status(401).json({ error: 'Unauthorized' });\n}\n\n// Authorization: Can THIS user access THIS resource?\nif (post.authorId !== user.id) {\n  return res.status(403).json({ error: 'Forbidden' });\n}\n","text",[81,82,78],"code",{"__ignoreMap":83},"",[28,85,87],{"id":86},"step-by-step-guide","Step-by-Step Guide",[89,90,92,97,104],"step",{"number":91},"1",[93,94,96],"h3",{"id":95},"create-authentication-middleware-nextjs","Create authentication middleware (Next.js)",[18,98,99,100,103],{},"Create ",[81,101,102],{},"middleware.ts"," in your project root:",[74,105,108],{"className":106,"code":107,"language":79},[77],"import { NextResponse } from 'next/server';\nimport type { NextRequest } from 'next/server';\nimport { getToken } from 'next-auth/jwt';  // For NextAuth\n// Or use your auth library's method\n\nexport async function middleware(request: NextRequest) {\n  // Get the pathname\n  const path = request.nextUrl.pathname;\n\n  // Define public paths that don't require auth\n  const publicPaths = ['/', '/login', '/signup', '/about', '/api/auth'];\n  const isPublicPath = publicPaths.some(p =>\n    path === p || path.startsWith(p + '/')\n  );\n\n  if (isPublicPath) {\n    return NextResponse.next();\n  }\n\n  // Check authentication\n  const token = await getToken({\n    req: request,\n    secret: process.env.NEXTAUTH_SECRET\n  });\n\n  // No token = not authenticated\n  if (!token) {\n    // For API routes, return 401\n    if (path.startsWith('/api/')) {\n      return NextResponse.json(\n        { error: 'Authentication required' },\n        { status: 401 }\n      );\n    }\n\n    // For pages, redirect to login\n    const loginUrl = new URL('/login', request.url);\n    loginUrl.searchParams.set('callbackUrl', path);\n    return NextResponse.redirect(loginUrl);\n  }\n\n  // User is authenticated, continue\n  return NextResponse.next();\n}\n\n// Configure which paths use this middleware\nexport const config = {\n  matcher: [\n    /*\n     * Match all paths except:\n     * - _next/static (static files)\n     * - _next/image (image optimization)\n     * - favicon.ico\n     * - public folder\n     */\n    '/((?!_next/static|_next/image|favicon.ico|public/).*)',\n  ],\n};\n",[81,109,107],{"__ignoreMap":83},[89,111,113,117,120],{"number":112},"2",[93,114,116],{"id":115},"add-role-based-route-protection","Add role-based route protection",[18,118,119],{},"Extend middleware for role-based access:",[74,121,124],{"className":122,"code":123,"language":79},[77],"import { NextResponse } from 'next/server';\nimport type { NextRequest } from 'next/server';\nimport { getToken } from 'next-auth/jwt';\n\n// Define protected routes and required roles\nconst protectedRoutes: Record\u003Cstring, string[]> = {\n  '/admin': ['admin'],\n  '/admin/users': ['admin'],\n  '/dashboard': ['user', 'admin'],\n  '/settings': ['user', 'admin'],\n  '/moderator': ['moderator', 'admin'],\n};\n\nexport async function middleware(request: NextRequest) {\n  const path = request.nextUrl.pathname;\n\n  // Check if path requires specific roles\n  const requiredRoles = Object.entries(protectedRoutes).find(\n    ([route]) => path.startsWith(route)\n  )?.[1];\n\n  if (!requiredRoles) {\n    return NextResponse.next();\n  }\n\n  const token = await getToken({\n    req: request,\n    secret: process.env.NEXTAUTH_SECRET\n  });\n\n  // Not authenticated\n  if (!token) {\n    if (path.startsWith('/api/')) {\n      return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });\n    }\n    return NextResponse.redirect(new URL('/login', request.url));\n  }\n\n  // Check role authorization\n  const userRole = token.role as string || 'user';\n\n  if (!requiredRoles.includes(userRole)) {\n    if (path.startsWith('/api/')) {\n      return NextResponse.json({ error: 'Forbidden' }, { status: 403 });\n    }\n    // Redirect to access denied page or dashboard\n    return NextResponse.redirect(new URL('/access-denied', request.url));\n  }\n\n  return NextResponse.next();\n}\n",[81,125,123],{"__ignoreMap":83},[89,127,129,133,136],{"number":128},"3",[93,130,132],{"id":131},"protect-api-routes-double-check-pattern","Protect API routes (double-check pattern)",[18,134,135],{},"Even with middleware, always verify in your API handlers:",[74,137,140],{"className":138,"code":139,"language":79},[77],"// app/api/posts/[id]/route.ts (Next.js App Router)\nimport { getServerSession } from 'next-auth';\nimport { authOptions } from '@/lib/auth';\nimport { NextResponse } from 'next/server';\nimport { db } from '@/lib/db';\n\nexport async function GET(\n  request: Request,\n  { params }: { params: { id: string } }\n) {\n  // 1. Authentication check\n  const session = await getServerSession(authOptions);\n\n  if (!session?.user) {\n    return NextResponse.json(\n      { error: 'Authentication required' },\n      { status: 401 }\n    );\n  }\n\n  // 2. Fetch the resource\n  const post = await db.post.findUnique({\n    where: { id: params.id }\n  });\n\n  if (!post) {\n    return NextResponse.json(\n      { error: 'Post not found' },\n      { status: 404 }\n    );\n  }\n\n  // 3. Authorization check - can this user access this post?\n  const isOwner = post.authorId === session.user.id;\n  const isPublished = post.status === 'published';\n  const isAdmin = session.user.role === 'admin';\n\n  if (!isPublished && !isOwner && !isAdmin) {\n    return NextResponse.json(\n      { error: 'You do not have access to this post' },\n      { status: 403 }\n    );\n  }\n\n  return NextResponse.json(post);\n}\n\nexport async function DELETE(\n  request: Request,\n  { params }: { params: { id: string } }\n) {\n  const session = await getServerSession(authOptions);\n\n  if (!session?.user) {\n    return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });\n  }\n\n  const post = await db.post.findUnique({\n    where: { id: params.id }\n  });\n\n  if (!post) {\n    return NextResponse.json({ error: 'Not found' }, { status: 404 });\n  }\n\n  // Only owner or admin can delete\n  if (post.authorId !== session.user.id && session.user.role !== 'admin') {\n    return NextResponse.json({ error: 'Forbidden' }, { status: 403 });\n  }\n\n  await db.post.delete({ where: { id: params.id } });\n\n  return NextResponse.json({ success: true });\n}\n",[81,141,139],{"__ignoreMap":83},[89,143,145,149],{"number":144},"4",[93,146,148],{"id":147},"create-reusable-auth-utilities","Create reusable auth utilities",[74,150,153],{"className":151,"code":152,"language":79},[77],"// lib/auth-utils.ts\nimport { getServerSession } from 'next-auth';\nimport { authOptions } from '@/lib/auth';\nimport { NextResponse } from 'next/server';\n\ntype AuthResult =\n  | { success: true; user: { id: string; email: string; role: string } }\n  | { success: false; response: NextResponse };\n\nexport async function requireAuth(): Promise\u003CAuthResult> {\n  const session = await getServerSession(authOptions);\n\n  if (!session?.user) {\n    return {\n      success: false,\n      response: NextResponse.json(\n        { error: 'Authentication required' },\n        { status: 401 }\n      )\n    };\n  }\n\n  return {\n    success: true,\n    user: {\n      id: session.user.id,\n      email: session.user.email!,\n      role: session.user.role || 'user'\n    }\n  };\n}\n\nexport async function requireRole(\n  allowedRoles: string[]\n): Promise\u003CAuthResult> {\n  const authResult = await requireAuth();\n\n  if (!authResult.success) {\n    return authResult;\n  }\n\n  if (!allowedRoles.includes(authResult.user.role)) {\n    return {\n      success: false,\n      response: NextResponse.json(\n        { error: 'Insufficient permissions' },\n        { status: 403 }\n      )\n    };\n  }\n\n  return authResult;\n}\n\n// Usage in API route\nexport async function GET(request: Request) {\n  const auth = await requireAuth();\n  if (!auth.success) return auth.response;\n\n  // auth.user is now typed and available\n  const data = await fetchUserData(auth.user.id);\n  return NextResponse.json(data);\n}\n\n// Admin-only route\nexport async function DELETE(request: Request) {\n  const auth = await requireRole(['admin']);\n  if (!auth.success) return auth.response;\n\n  // Only admins reach here\n  await performAdminAction();\n  return NextResponse.json({ success: true });\n}\n",[81,154,152],{"__ignoreMap":83},[89,156,158,162],{"number":157},"5",[93,159,161],{"id":160},"protect-server-components-nextjs-app-router","Protect Server Components (Next.js App Router)",[74,163,166],{"className":164,"code":165,"language":79},[77],"// app/dashboard/page.tsx\nimport { getServerSession } from 'next-auth';\nimport { authOptions } from '@/lib/auth';\nimport { redirect } from 'next/navigation';\n\nexport default async function DashboardPage() {\n  const session = await getServerSession(authOptions);\n\n  if (!session) {\n    redirect('/login?callbackUrl=/dashboard');\n  }\n\n  // Fetch user-specific data\n  const data = await fetchDashboardData(session.user.id);\n\n  return (\n    \u003Cdiv>\n      \u003Ch1>Welcome, {session.user.name}\u003C/h1>\n      {/* Render dashboard */}\n    \u003C/div>\n  );\n}\n\n// Admin page with role check\n// app/admin/page.tsx\nexport default async function AdminPage() {\n  const session = await getServerSession(authOptions);\n\n  if (!session) {\n    redirect('/login');\n  }\n\n  if (session.user.role !== 'admin') {\n    redirect('/access-denied');\n  }\n\n  return (\n    \u003Cdiv>\n      \u003Ch1>Admin Dashboard\u003C/h1>\n      {/* Admin content */}\n    \u003C/div>\n  );\n}\n",[81,167,165],{"__ignoreMap":83},[89,169,171,175,178],{"number":170},"6",[93,172,174],{"id":173},"add-client-side-route-guards-react","Add client-side route guards (React)",[18,176,177],{},"Client guards improve UX but are NOT security - always verify server-side:",[74,179,182],{"className":180,"code":181,"language":79},[77],"// components/ProtectedRoute.tsx\n'use client';\n\nimport { useSession } from 'next-auth/react';\nimport { useRouter, usePathname } from 'next/navigation';\nimport { useEffect } from 'react';\n\ninterface ProtectedRouteProps {\n  children: React.ReactNode;\n  requiredRoles?: string[];\n}\n\nexport function ProtectedRoute({\n  children,\n  requiredRoles\n}: ProtectedRouteProps) {\n  const { data: session, status } = useSession();\n  const router = useRouter();\n  const pathname = usePathname();\n\n  useEffect(() => {\n    if (status === 'loading') return;\n\n    if (!session) {\n      router.push(`/login?callbackUrl=${encodeURIComponent(pathname)}`);\n      return;\n    }\n\n    if (requiredRoles && !requiredRoles.includes(session.user.role)) {\n      router.push('/access-denied');\n    }\n  }, [session, status, router, pathname, requiredRoles]);\n\n  if (status === 'loading') {\n    return \u003Cdiv>Loading...\u003C/div>;\n  }\n\n  if (!session) {\n    return null;  // Will redirect\n  }\n\n  if (requiredRoles && !requiredRoles.includes(session.user.role)) {\n    return null;  // Will redirect\n  }\n\n  return \u003C>{children}\u003C/>;\n}\n\n// Usage\nexport default function SettingsPage() {\n  return (\n    \u003CProtectedRoute>\n      \u003CSettings />\n    \u003C/ProtectedRoute>\n  );\n}\n\n// Admin page\nexport default function AdminPage() {\n  return (\n    \u003CProtectedRoute requiredRoles={['admin']}>\n      \u003CAdminDashboard />\n    \u003C/ProtectedRoute>\n  );\n}\n",[81,183,181],{"__ignoreMap":83},[89,185,187,191],{"number":186},"7",[93,188,190],{"id":189},"implement-resource-level-authorization","Implement resource-level authorization",[74,192,195],{"className":193,"code":194,"language":79},[77],"// lib/permissions.ts\ntype Resource = 'post' | 'comment' | 'user' | 'settings';\ntype Action = 'read' | 'create' | 'update' | 'delete';\n\ninterface User {\n  id: string;\n  role: string;\n}\n\ninterface ResourceOwnership {\n  ownerId?: string;\n  isPublic?: boolean;\n}\n\nexport function canAccess(\n  user: User | null,\n  resource: Resource,\n  action: Action,\n  ownership?: ResourceOwnership\n): boolean {\n  // Unauthenticated users\n  if (!user) {\n    // Can only read public resources\n    return action === 'read' && ownership?.isPublic === true;\n  }\n\n  // Admins can do anything\n  if (user.role === 'admin') {\n    return true;\n  }\n\n  // Check ownership for user-owned resources\n  if (ownership?.ownerId) {\n    const isOwner = ownership.ownerId === user.id;\n\n    switch (action) {\n      case 'read':\n        return isOwner || ownership.isPublic === true;\n      case 'update':\n      case 'delete':\n        return isOwner;\n      case 'create':\n        return true;  // Anyone can create their own\n    }\n  }\n\n  // Default permissions by role\n  const rolePermissions: Record\u003Cstring, Record\u003CResource, Action[]>> = {\n    user: {\n      post: ['read', 'create'],\n      comment: ['read', 'create'],\n      user: ['read'],\n      settings: []\n    },\n    moderator: {\n      post: ['read', 'create', 'update'],\n      comment: ['read', 'create', 'update', 'delete'],\n      user: ['read'],\n      settings: []\n    }\n  };\n\n  return rolePermissions[user.role]?.[resource]?.includes(action) ?? false;\n}\n\n// Usage in API route\nexport async function PUT(request: Request, { params }) {\n  const auth = await requireAuth();\n  if (!auth.success) return auth.response;\n\n  const post = await db.post.findUnique({ where: { id: params.id } });\n\n  if (!canAccess(auth.user, 'post', 'update', { ownerId: post?.authorId })) {\n    return NextResponse.json({ error: 'Forbidden' }, { status: 403 });\n  }\n\n  // Proceed with update...\n}\n",[81,196,194],{"__ignoreMap":83},[89,198,200,204],{"number":199},"8",[93,201,203],{"id":202},"expressjs-nodejs-api-protection","Express.js / Node.js API protection",[74,205,208],{"className":206,"code":207,"language":79},[77],"// middleware/auth.js\nimport jwt from 'jsonwebtoken';\n\nexport function authenticate(req, res, next) {\n  const authHeader = req.headers.authorization;\n\n  if (!authHeader?.startsWith('Bearer ')) {\n    return res.status(401).json({ error: 'No token provided' });\n  }\n\n  const token = authHeader.split(' ')[1];\n\n  try {\n    const decoded = jwt.verify(token, process.env.JWT_SECRET);\n    req.user = decoded;\n    next();\n  } catch (error) {\n    return res.status(401).json({ error: 'Invalid token' });\n  }\n}\n\nexport function authorize(...allowedRoles) {\n  return (req, res, next) => {\n    if (!req.user) {\n      return res.status(401).json({ error: 'Not authenticated' });\n    }\n\n    if (!allowedRoles.includes(req.user.role)) {\n      return res.status(403).json({ error: 'Insufficient permissions' });\n    }\n\n    next();\n  };\n}\n\n// Usage\nimport express from 'express';\nimport { authenticate, authorize } from './middleware/auth.js';\n\nconst app = express();\n\n// Public route\napp.get('/api/posts', async (req, res) => {\n  const posts = await db.post.findMany({ where: { status: 'published' } });\n  res.json(posts);\n});\n\n// Authenticated route\napp.post('/api/posts', authenticate, async (req, res) => {\n  const post = await db.post.create({\n    data: { ...req.body, authorId: req.user.id }\n  });\n  res.json(post);\n});\n\n// Admin-only route\napp.delete('/api/users/:id', authenticate, authorize('admin'), async (req, res) => {\n  await db.user.delete({ where: { id: req.params.id } });\n  res.json({ success: true });\n});\n",[81,209,207],{"__ignoreMap":83},[211,212,214],"h4",{"id":213},"security-checklist","Security Checklist",[33,216,217,220,223,226,229,232,235,238],{},[36,218,219],{},"All sensitive API routes verify authentication server-side",[36,221,222],{},"Authorization checks verify the user can access the specific resource",[36,224,225],{},"401 is returned for unauthenticated requests",[36,227,228],{},"403 is returned for unauthorized requests (authenticated but not permitted)",[36,230,231],{},"Client-side guards are used for UX only, not security",[36,233,234],{},"Middleware provides first layer of protection",[36,236,237],{},"API handlers double-check auth (defense in depth)",[36,239,240],{},"Error messages don't leak information about resources",[28,242,244],{"id":243},"how-to-verify-it-worked","How to Verify It Worked",[246,247,248,254,260,266,272],"ol",{},[36,249,250,253],{},[63,251,252],{},"Test unauthenticated access:"," Call API without token - should get 401",[36,255,256,259],{},[63,257,258],{},"Test unauthorized access:"," Access another user's resource - should get 403",[36,261,262,265],{},[63,263,264],{},"Test role restrictions:"," Access admin route as regular user - should get 403",[36,267,268,271],{},[63,269,270],{},"Test bypass attempts:"," Try calling API directly, skipping UI - should still be blocked",[36,273,274,277],{},[63,275,276],{},"Test with curl/Postman:"," Manually craft requests to verify server-side protection",[74,279,282],{"className":280,"code":281,"language":79},[77],"# Test unauthenticated\ncurl http://localhost:3000/api/posts/123\n# Expected: 401 Unauthorized\n\n# Test with invalid token\ncurl -H \"Authorization: Bearer invalid\" http://localhost:3000/api/posts/123\n# Expected: 401 Invalid token\n\n# Test accessing another user's private resource\ncurl -H \"Authorization: Bearer $USER_A_TOKEN\" http://localhost:3000/api/posts/user-b-private-post\n# Expected: 403 Forbidden\n",[81,283,281],{"__ignoreMap":83},[28,285,287],{"id":286},"common-errors-troubleshooting","Common Errors & Troubleshooting",[211,289,291],{"id":290},"middleware-not-running","Middleware not running",[18,293,294],{},"Check your matcher config in middleware.ts. Ensure the path patterns match your routes. Remember middleware runs on the Edge Runtime - some Node.js APIs aren't available.",[211,296,298],{"id":297},"getserversession-returns-null","getServerSession returns null",[18,300,301],{},"Ensure you're passing the correct authOptions. In App Router, make sure you're calling it in a Server Component or Route Handler, not a Client Component.",[211,303,305],{"id":304},"redirect-loops","Redirect loops",[18,307,308],{},"Your login page is probably being protected by middleware. Add it to the public paths list or exclude it from the matcher.",[211,310,312],{"id":311},"cors-errors-on-api-calls","CORS errors on API calls",[18,314,315],{},"If your API returns 401/403 before CORS headers are set, browsers show CORS errors. Ensure your error responses include proper CORS headers.",[211,317,319],{"id":318},"token-not-included-in-requests","Token not included in requests",[18,321,322,323,326],{},"For httpOnly cookies, ensure ",[81,324,325],{},"credentials: 'include'"," in fetch calls. For Bearer tokens, check your auth context is providing the token to your HTTP client.",[328,329,330,337,343,349],"faq-section",{},[331,332,334],"faq-item",{"question":333},"Is middleware enough, or do I need to check in API routes too?",[18,335,336],{},"Both. Middleware provides a first layer of defense, but always verify in your API handlers too (defense in depth). Middleware can be bypassed in certain edge cases, and authorization logic often needs access to the specific resource being requested.",[331,338,340],{"question":339},"Should I use 401 or 403 for unauthorized access?",[18,341,342],{},"Use 401 Unauthorized when the user is not authenticated (no token or invalid token). Use 403 Forbidden when the user is authenticated but doesn't have permission to access the resource. This distinction helps clients know whether to prompt for login vs show an access denied message.",[331,344,346],{"question":345},"How do I protect static files?",[18,347,348],{},"Next.js middleware can protect routes, but not files in /public. For protected files, serve them through API routes that check auth, or use signed URLs from cloud storage (S3, GCS) with short expiration times.",[331,350,352],{"question":351},"What about protecting GraphQL endpoints?",[18,353,354,355,358,359,362],{},"GraphQL typically has a single endpoint. Implement auth in your resolver context, then check permissions in each resolver. Use directives like ",[81,356,357],{},"@auth"," or ",[81,360,361],{},"@hasRole"," for declarative authorization. Libraries like graphql-shield can help.",[18,364,365,368,373,374,373,378,373,382],{},[63,366,367],{},"Related guides:",[369,370,372],"a",{"href":371},"/blog/how-to/add-authentication-nextjs","Add Auth to Next.js"," ·\n",[369,375,377],{"href":376},"/blog/how-to/supabase-auth","Supabase Auth Setup",[369,379,381],{"href":380},"/blog/how-to/firebase-auth","Firebase Auth Setup",[369,383,385],{"href":384},"/blog/how-to/jwt-security","JWT Security",[387,388,389,395,400],"related-articles",{},[390,391],"related-card",{"description":392,"href":393,"title":394},"Complete guide to configuring environment variables in Netlify. Set up secrets for builds, functions, and different depl","/blog/how-to/netlify-env-vars","How to Set Up Netlify Environment Variables",[390,396],{"description":397,"href":398,"title":399},"Step-by-step guide to adding security headers on Netlify. Configure via _headers file, netlify.toml, and Edge Functions.","/blog/how-to/netlify-headers","How to Configure Security Headers on Netlify",[390,401],{"description":402,"href":403,"title":404},"Complete guide to secure NextAuth.js setup. Configure providers, protect API routes, secure sessions with database adapt","/blog/how-to/nextauth-setup","How to Set Up NextAuth.js Securely",{"title":83,"searchDepth":406,"depth":406,"links":407},2,[408,409,410,421,422],{"id":30,"depth":406,"text":31},{"id":56,"depth":406,"text":57},{"id":86,"depth":406,"text":87,"children":411},[412,414,415,416,417,418,419,420],{"id":95,"depth":413,"text":96},3,{"id":115,"depth":413,"text":116},{"id":131,"depth":413,"text":132},{"id":147,"depth":413,"text":148},{"id":160,"depth":413,"text":161},{"id":173,"depth":413,"text":174},{"id":189,"depth":413,"text":190},{"id":202,"depth":413,"text":203},{"id":243,"depth":406,"text":244},{"id":286,"depth":406,"text":287},"how-to","2026-01-21","2026-01-30","Step-by-step guide to protecting routes and API endpoints. Implement middleware patterns, authentication guards, authorization checks, and secure Next.js/React routes.",false,"md",null,"yellow",{},true,"Complete guide to implementing authentication guards and authorization middleware.","/blog/how-to/protect-routes","[object Object]","HowTo",{"title":5,"description":426},{"loc":434},"blog/how-to/protect-routes",[],"summary_large_image","H0YNotSGFQyCICaVGrNOzTw_HfbedxW7AW-IdVYFOfw",1775843927874]