Protecting Your Pages
Configure Middleware
If you plan to use Next.js API routes or server-side rendering with getAuth
, you must install withClerkMiddleware
in your Next.js middleware. Otherwise, you can skip this step.
Copy this snippet into your project root file named middleware.js or middleware.ts.
1import { withClerkMiddleware } from "@clerk/nextjs/server";2import { NextResponse } from "next/server";3import type { NextRequest } from 'next/server'45export default withClerkMiddleware((req: NextRequest) => {6return NextResponse.next();7});89// Stop Middleware running on static files10export const config = { matcher: '/((?!_next/image|_next/static|favicon.ico).*)'};
1import { withClerkMiddleware } from "@clerk/nextjs/server";2import { NextResponse } from "next/server";34export default withClerkMiddleware((req) => {5return NextResponse.next();6});78// Stop Middleware running on static files9export const config = { matcher: '/((?!_next/image|_next/static|favicon.ico).*)'};10
Clerk only depends on the withClerkMiddleware()
wrapper. You are welcome to customize the internal middleware function as needed.
Using Middleware is the most comprehensive way to implement page protection in your app. Below is an example of page protection using Middleware.
1import { withClerkMiddleware, getAuth } from '@clerk/nextjs/server'2import { NextResponse } from 'next/server'3import type { NextRequest } from 'next/server'45// Set the paths that don't require the user to be signed in6const publicPaths = ['/', '/sign-in*', '/sign-up*']78const isPublic = (path: string) => {9return publicPaths.find(x =>10path.match(new RegExp(`^${x}$`.replace('*$', '($|/)')))11)12}1314export default withClerkMiddleware((request: NextRequest) => {15if (isPublic(request.nextUrl.pathname)) {16return NextResponse.next()17}18// if the user is not signed in redirect them to the sign in page.19const { userId } = getAuth(request)2021if (!userId) {22// redirect the users to /pages/sign-in/[[...index]].ts2324const signInUrl = new URL('/sign-in', request.url)25signInUrl.searchParams.set('redirect_url', request.url)26return NextResponse.redirect(signInUrl)27}28return NextResponse.next()29})3031export const config = { matcher: '/((?!_next/image|_next/static|favicon.ico).*)'};
1import { withClerkMiddleware, getAuth } from '@clerk/nextjs/server'2import { NextResponse } from 'next/server'34// Set the paths that don't require the user to be signed in5const publicPaths = ['/', '/sign-in*', '/sign-up*']67const isPublic = (path) => {8return publicPaths.find(x =>9path.match(new RegExp(`^${x}$`.replace('*$', '($|/)')))10)11}1213export default withClerkMiddleware((request) => {14if (isPublic(request.nextUrl.pathname)) {15return NextResponse.next()16}17// if the user is not signed in redirect them to the sign in page.18const { userId } = getAuth(request)1920if (!userId) {21// redirect the users to /pages/sign-in/[[...index]].ts2223const signInUrl = new URL('/sign-in', request.url)24signInUrl.searchParams.set('redirect_url', request.url)25return NextResponse.redirect(signInUrl)26}27return NextResponse.next()28})2930export const config = { matcher: '/((?!_next/image|_next/static|favicon.ico).*)'};
Control Components
If you prefer to use Clerk's Control Components for page protection, the following example shows you how to compose control components in _app at the root of your /pages directory.
1import {2ClerkProvider,3SignedIn,4SignedOut,5RedirectToSignIn,6} from "@clerk/nextjs";7import { AppProps } from "next/app";8import { useRouter } from "next/router";910// List pages you want to be publicly accessible, or leave empty if11// every page requires authentication. Use this naming strategy:12// "/" for pages/index.js13// "/foo" for pages/foo/index.js14// "/foo/bar" for pages/foo/bar.js15// "/foo/[...bar]" for pages/foo/[...bar].js16const publicPages : Array<string> = [];1718function MyApp({ Component, pageProps } : AppProps) {19// Get the pathname20const { pathname } = useRouter();2122// Check if the current route matches a public page23const isPublicPage = publicPages.includes(pathname);2425// If the current route is listed as public, render it directly26// Otherwise, use Clerk to require authentication27return (28<ClerkProvider {...pageProps}>29{isPublicPage ? (30<Component {...pageProps} />31) : (32<>33<SignedIn>34<Component {...pageProps} />35</SignedIn>36<SignedOut>37<RedirectToSignIn />38</SignedOut>39</>40)}41</ClerkProvider>42);43}4445export default MyApp;
1import { ClerkProvider, SignedIn, SignedOut, RedirectToSignIn } from '@clerk/nextjs';2import { useRouter } from 'next/router';34// List pages you want to be publicly accessible, or leave empty if5// every page requires authentication. Use this naming strategy:6// "/" for pages/index.js7// "/foo" for pages/foo/index.js8// "/foo/bar" for pages/foo/bar.js9// "/foo/[...bar]" for pages/foo/[...bar].js10const publicPages = [];1112function MyApp({ Component, pageProps }) {13// Get the pathname14const { pathname } = useRouter();1516// Check if the current route matches a public page17const isPublicPage = publicPages.includes(pathname);1819// If the current route is listed as public, render it directly20// Otherwise, use Clerk to require authentication21return (22<ClerkProvider {...pageProps}>23{isPublicPage ? (24<Component {...pageProps} />25) : (26<>27<SignedIn>28<Component {...pageProps} />29</SignedIn>30<SignedOut>31<RedirectToSignIn />32</SignedOut>33</>34)}35</ClerkProvider>36);37}3839export default MyApp;