Clerk logo

Clerk Docs

Ctrl + K
Go to clerk.com
Check out a preview of our new docs.

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.

1
import { withClerkMiddleware } from "@clerk/nextjs/server";
2
import { NextResponse } from "next/server";
3
import type { NextRequest } from 'next/server'
4
5
export default withClerkMiddleware((req: NextRequest) => {
6
return NextResponse.next();
7
});
8
9
// Stop Middleware running on static files
10
export const config = { matcher: '/((?!_next/image|_next/static|favicon.ico).*)'};
1
import { withClerkMiddleware } from "@clerk/nextjs/server";
2
import { NextResponse } from "next/server";
3
4
export default withClerkMiddleware((req) => {
5
return NextResponse.next();
6
});
7
8
// Stop Middleware running on static files
9
export 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.

1
import { withClerkMiddleware, getAuth } from '@clerk/nextjs/server'
2
import { NextResponse } from 'next/server'
3
import type { NextRequest } from 'next/server'
4
5
// Set the paths that don't require the user to be signed in
6
const publicPaths = ['/', '/sign-in*', '/sign-up*']
7
8
const isPublic = (path: string) => {
9
return publicPaths.find(x =>
10
path.match(new RegExp(`^${x}$`.replace('*$', '($|/)')))
11
)
12
}
13
14
export default withClerkMiddleware((request: NextRequest) => {
15
if (isPublic(request.nextUrl.pathname)) {
16
return NextResponse.next()
17
}
18
// if the user is not signed in redirect them to the sign in page.
19
const { userId } = getAuth(request)
20
21
if (!userId) {
22
// redirect the users to /pages/sign-in/[[...index]].ts
23
24
const signInUrl = new URL('/sign-in', request.url)
25
signInUrl.searchParams.set('redirect_url', request.url)
26
return NextResponse.redirect(signInUrl)
27
}
28
return NextResponse.next()
29
})
30
31
export const config = { matcher: '/((?!_next/image|_next/static|favicon.ico).*)'};
1
import { withClerkMiddleware, getAuth } from '@clerk/nextjs/server'
2
import { NextResponse } from 'next/server'
3
4
// Set the paths that don't require the user to be signed in
5
const publicPaths = ['/', '/sign-in*', '/sign-up*']
6
7
const isPublic = () => {
8
return publicPaths.find(x =>
9
path.match(new RegExp(`^${x}$`.replace('*$', '($|/)')))
10
)
11
}
12
13
export default withClerkMiddleware((request) => {
14
if (isPublic(request.nextUrl.pathname)) {
15
return NextResponse.next()
16
}
17
// if the user is not signed in redirect them to the sign in page.
18
const { userId } = getAuth(request)
19
20
if (!userId) {
21
// redirect the users to /pages/sign-in/[[...index]].ts
22
23
const signInUrl = new URL('/sign-in', request.url)
24
signInUrl.searchParams.set('redirect_url', request.url)
25
return NextResponse.redirect(signInUrl)
26
}
27
return NextResponse.next()
28
})
29
30
export 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.

1
import {
2
ClerkProvider,
3
SignedIn,
4
SignedOut,
5
RedirectToSignIn,
6
} from "@clerk/nextjs";
7
import { AppProps } from "next/app";
8
import { useRouter } from "next/router";
9
10
// List pages you want to be publicly accessible, or leave empty if
11
// every page requires authentication. Use this naming strategy:
12
// "/" for pages/index.js
13
// "/foo" for pages/foo/index.js
14
// "/foo/bar" for pages/foo/bar.js
15
// "/foo/[...bar]" for pages/foo/[...bar].js
16
const publicPages : Array<string> = [];
17
18
function MyApp({ Component, pageProps } : AppProps) {
19
// Get the pathname
20
const { pathname } = useRouter();
21
22
// Check if the current route matches a public page
23
const isPublicPage = publicPages.includes(pathname);
24
25
// If the current route is listed as public, render it directly
26
// Otherwise, use Clerk to require authentication
27
return (
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
}
44
45
export default MyApp;
1
import { ClerkProvider, SignedIn, SignedOut, RedirectToSignIn } from '@clerk/nextjs';
2
import { useRouter } from 'next/router';
3
4
// List pages you want to be publicly accessible, or leave empty if
5
// every page requires authentication. Use this naming strategy:
6
// "/" for pages/index.js
7
// "/foo" for pages/foo/index.js
8
// "/foo/bar" for pages/foo/bar.js
9
// "/foo/[...bar]" for pages/foo/[...bar].js
10
const publicPages = [];
11
12
function MyApp({ Component, pageProps }) {
13
// Get the pathname
14
const { pathname } = useRouter();
15
16
// Check if the current route matches a public page
17
const isPublicPage = publicPages.includes(pathname);
18
19
// If the current route is listed as public, render it directly
20
// Otherwise, use Clerk to require authentication
21
return (
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
}
38
39
export default MyApp;

Was this helpful?

Clerk © 2023