Back to Rules
Next.js94% popularity

Next.js Middleware Authentication

Implement authentication at the edge with Next.js Middleware for protected routes.

Next.js TeamUpdated Mar 8, 2024

Overview

Next.js Middleware runs before requests complete, enabling authentication and authorization checks at the edge without hitting your application code. This approach reduces latency by rejecting unauthorized requests early and offloads common security checks from your application servers. Middleware receives a NextRequest object and can inspect cookies, headers, and other request properties. For JWT-based authentication, the token can be verified using libraries like jose that work in edge runtimes. If validation fails, NextResponse.redirect() immediately sends the user to a login page without ever invoking page components or API routes. Protected routes are configured using the matcher option in middleware config. This allows precise control over which paths require authentication while avoiding middleware overhead on static assets and public routes. Multiple matchers can be combined with negative patterns for exclusions. The middleware approach has trade-offs compared to higher-level solutions. It cannot access database directly (relying on JWT or stateless tokens), and it executes on every matching request before cache. For complex authorization rules requiring database lookups, middleware should verify basic auth and let page-level checks handle fine-grained permissions. Edge runtime constraints affect available APIs. Node.js-specific features like Buffer or crypto require using web-compatible equivalents. Database drivers often don't work in edge runtime; if you need database authorization checks, consider using a lightweight API call or accepting that full auth happens in application code after middleware passes.

Code Example

.nextjsrules
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
import { jwtVerify } from 'jose';

const JWT_SECRET = new TextEncoder().encode(
  process.env.JWT_SECRET || 'development-secret-key'
);

const publicPaths = ['/login', '/register', '/api/auth', '/public'];

export async function middleware(request: NextRequest) {
  const { pathname } = request.nextUrl;

  // Allow public paths without authentication
  if (publicPaths.some(path => pathname.startsWith(path))) {
    return NextResponse.next();
  }

  // Skip middleware for static files and images
  if (
    pathname.startsWith('/_next') ||
    pathname.startsWith('/favicon') ||
    pathname.includes('.')
  ) {
    return NextResponse.next();
  }

  // Extract token from cookie or Authorization header
  const token = request.cookies.get('auth_token')?.value ||
                request.headers.get('Authorization')?.replace('Bearer ', '');

  if (!token) {
    const loginUrl = new URL('/login', request.url);
    loginUrl.searchParams.set('redirect', pathname);
    return NextResponse.redirect(loginUrl);
  }

  try {
    const { payload } = await jwtVerify(token, JWT_SECRET);

    // Add user info to headers for downstream use
    const requestHeaders = new Headers(request.headers);
    requestHeaders.set('x-user-id', payload.sub as string);
    requestHeaders.set('x-user-role', payload.role as string);

    // Check admin routes
    if (pathname.startsWith('/admin') && payload.role !== 'admin') {
      return NextResponse.redirect(new URL('/unauthorized', request.url));
    }

    return NextResponse.next({
      request: {
        headers: requestHeaders,
      },
    });
  } catch (error) {
    // Invalid or expired token
    const response = NextResponse.redirect(new URL('/login', request.url));
    response.cookies.delete('auth_token');
    return response;
  }
}

export const config = {
  matcher: [
    '/((?!_next/static|_next/image|favicon.ico|public).*)',
  ],
};

More Next.js Rules

NEXTJS
98%

Next.js App Router Server Components First

Prioritize React Server Components for data fetching and static content. Client components only when interactivity is required.

server-componentsapp-routerperformance
'use server';

import { db } from '@/lib/database';
import { cache } from 'react';

export const getProjects = cache(async () => {
  return db.project...
Jan 15, 2024by Vercel Engineering
View Rule
NEXTJS
93%

Next.js Image Optimization Best Practices

Use the Image component with proper sizing, formats, and loading strategies for maximum performance.

nextjsimage-optimizationperformance
import Image from 'next/image';
import Link from 'next/link';

export function ProjectCard({ project }: { project: Project }) {
  return (
    <Link h...
Feb 28, 2024by Vercel
View Rule
NEXTJS
92%

Next.js Dynamic Metadata API

Use the Metadata API for SEO optimization with dynamic titles, descriptions, and OpenGraph images.

nextjsseometadata
import { Metadata, ResolvingMetadata } from 'next';
import { notFound } from 'next/navigation';
import { db } from '@/lib/db';
import { SchemaMarkup }...
Mar 18, 2024by Vercel
View Rule