Bird
Raised Fist0
NextJSframework~10 mins

Protected routes with middleware in NextJS - Step-by-Step Execution

Choose your learning style10 modes available

Start learning this pattern below

Jump into concepts and practice - no test required

or
Recommended
Test this pattern10 questions across easy, medium, and hard to know if this pattern is strong
Concept Flow - Protected routes with middleware
User Request URL
Middleware Intercepts Request
Check Authentication Token
Allow Access
Render Page
The middleware checks if the user is authenticated before allowing access to protected pages. If not authenticated, it redirects to login.
Execution Sample
NextJS
import { NextResponse } from 'next/server';

export function middleware(request) {
  const pathname = request.nextUrl.pathname;
  if (pathname.startsWith('/dashboard') || pathname.startsWith('/profile')) {
    const token = request.cookies.get('token');
    if (!token) return NextResponse.redirect(new URL('/login', request.url));
  }
  return NextResponse.next();
}
Middleware checks for a token cookie; if missing, redirects to login; otherwise, allows the request.
Execution Table
StepRequest URLToken Present?Action TakenResult
1/dashboardNoRedirect to /loginUser sent to login page
2/dashboardYesAllow accessDashboard page rendered
3/profileNoRedirect to /loginUser sent to login page
4/profileYesAllow accessProfile page rendered
5/loginNoAllow accessLogin page rendered
6/loginYesAllow accessLogin page rendered
💡 Middleware stops by either redirecting unauthenticated users or allowing authenticated users to proceed.
Variable Tracker
VariableStartAfter Step 1After Step 2After Step 3After Step 4After Step 5After Step 6
tokenundefinedundefinedstring_tokenundefinedstring_tokenundefinedstring_token
request.url/dashboard/dashboard/dashboard/profile/profile/login/login
actionnoneredirectallowredirectallowallowallow
Key Moments - 2 Insights
Why does the middleware redirect some requests but not others?
Because the middleware checks if the token cookie exists (see execution_table rows 1 and 2). If no token, it redirects to login; if token exists, it allows access.
What happens if a user tries to access the login page while authenticated?
The middleware allows access (see execution_table rows 5 and 6). Middleware does not block login page regardless of token presence.
Visual Quiz - 3 Questions
Test your understanding
Look at the execution table, what action is taken at step 3 when token is missing?
ARender dashboard
BRedirect to /login
CAllow access
DThrow error
💡 Hint
Check the 'Action Taken' column at step 3 in the execution_table.
At which step does the middleware allow access to the profile page with a token?
AStep 4
BStep 3
CStep 5
DStep 6
💡 Hint
Look for the row with Request URL '/profile' and Token Present? 'Yes' in the execution_table.
If the token cookie is always missing, what will happen to requests for protected pages?
AThey will cause an error
BThey will be allowed
CThey will be redirected to /login
DThey will load normally
💡 Hint
Refer to the 'Token Present?' and 'Action Taken' columns in the execution_table for missing tokens.
Concept Snapshot
Protected routes use middleware to check authentication.
Middleware runs before page loads.
If token cookie missing, redirect to login.
If token present, allow page access.
This protects pages from unauthenticated users.
Full Transcript
This visual execution shows how Next.js middleware protects routes by checking for an authentication token cookie. When a user requests a page, the middleware intercepts the request and looks for the token. If the token is missing, the middleware redirects the user to the login page. If the token exists, the middleware allows the request to continue and the page renders normally. The execution table traces requests to different URLs with and without tokens, showing when redirects happen and when access is allowed. The variable tracker shows how the token and action variables change at each step. Key moments clarify why redirects happen and how login page access is handled. The quiz tests understanding of middleware decisions based on token presence. This helps beginners see step-by-step how protected routes work in Next.js middleware.

Practice

(1/5)
1. What is the main purpose of middleware in Next.js when protecting routes?
easy
A. To check user authentication before allowing access to certain pages
B. To style the pages dynamically based on user preferences
C. To preload images for faster page loading
D. To manage database connections automatically

Solution

  1. Step 1: Understand middleware role

    Middleware runs before a page loads to control access or modify requests.
  2. Step 2: Identify protection purpose

    In protected routes, middleware checks if a user is authenticated before allowing access.
  3. Final Answer:

    To check user authentication before allowing access to certain pages -> Option A
  4. Quick Check:

    Middleware protects routes by checking authentication [OK]
Hint: Middleware runs before page load to check user access [OK]
Common Mistakes:
  • Thinking middleware styles pages
  • Confusing middleware with database management
  • Assuming middleware preloads images
2. Which of the following is the correct way to export middleware in Next.js to protect routes?
easy
A. export function middleware() { /* code */ }
B. function middleware() { /* code */ } export middleware
C. export middleware = () => { /* code */ }
D. export default function middleware(req) { /* code */ }

Solution

  1. Step 1: Recall Next.js middleware export syntax

    Middleware must be exported as the default export function named middleware.
  2. Step 2: Check options for correct syntax

    Only export default function middleware(req) { /* code */ } uses "export default function middleware(req)" which is valid syntax.
  3. Final Answer:

    export default function middleware(req) { /* code */ } -> Option D
  4. Quick Check:

    Middleware uses default export function [OK]
Hint: Middleware must be default exported as a function named middleware [OK]
Common Mistakes:
  • Using named export instead of default
  • Assigning middleware to a variable without export default
  • Incorrect export statement syntax
3. Given this middleware code snippet, what happens when a user is not authenticated?
import { NextResponse } from 'next/server';

export default function middleware(req) {
  const token = req.cookies.get('token');
  if (!token) {
    return NextResponse.redirect(new URL('/login', req.url));
  }
  return NextResponse.next();
}
medium
A. The user stays on the current page without any change
B. The user is redirected to the /login page
C. The middleware throws an error and stops loading
D. The user is redirected to the homepage

Solution

  1. Step 1: Analyze token check in middleware

    The middleware checks if the 'token' cookie exists; if not, it triggers a redirect.
  2. Step 2: Understand redirect behavior

    If no token, middleware returns a redirect response to '/login' page.
  3. Final Answer:

    The user is redirected to the /login page -> Option B
  4. Quick Check:

    No token causes redirect to login [OK]
Hint: No token cookie means redirect to login page [OK]
Common Mistakes:
  • Assuming user stays on page without token
  • Thinking middleware throws error on missing token
  • Confusing redirect target URL
4. Identify the error in this middleware code that aims to protect routes:
import { NextResponse } from 'next/server';

export default function middleware(req) {
  const token = req.cookies.token;
  if (!token) {
    return NextResponse.redirect('/login');
  }
  return NextResponse.next();
}
medium
A. Missing async keyword in middleware function
B. Redirect URL should be absolute, not relative
C. Accessing cookies incorrectly; should use req.cookies.get('token')
D. NextResponse.next() should be replaced with NextResponse.continue()

Solution

  1. Step 1: Check cookie access method

    In Next.js middleware, cookies are accessed with req.cookies.get('token'), not req.cookies.token.
  2. Step 2: Verify redirect usage

    Redirect can accept a relative path, so that is valid here.
  3. Final Answer:

    Accessing cookies incorrectly; should use req.cookies.get('token') -> Option C
  4. Quick Check:

    Use req.cookies.get('token') to read cookies [OK]
Hint: Use req.cookies.get('token') to read cookies in middleware [OK]
Common Mistakes:
  • Using dot notation for cookies object
  • Thinking redirect URL must be absolute
  • Confusing NextResponse.next() with continue()
5. You want to protect only the routes starting with /dashboard using middleware. Which is the correct way to apply middleware only to these routes?
hard
A. export const config = { matcher: ['/dashboard/:path*'] };
B. export const config = { matcher: ['/dashboard*'] };
C. export const config = { matcher: ['/dashboard'] };
D. export const config = { matcher: ['/dashboard/**'] };

Solution

  1. Step 1: Understand matcher pattern syntax

    The matcher uses path patterns where ':path*' matches all subpaths under /dashboard.
  2. Step 2: Compare options for correct pattern

    export const config = { matcher: ['/dashboard/:path*'] }; uses '/dashboard/:path*' which correctly matches /dashboard and all nested routes.
  3. Final Answer:

    export const config = { matcher: ['/dashboard/:path*'] }; -> Option A
  4. Quick Check:

    Use '/dashboard/:path*' to match dashboard and subpaths [OK]
Hint: Use ':path*' to match all subpaths under a route [OK]
Common Mistakes:
  • Using wildcard * without colon for subpaths
  • Matching only exact /dashboard without subpaths
  • Using invalid glob pattern like /**