Skip to Content
You are viewing a beta version of Clerk Docs
Visit the latest docs
Clerk logo

Clerk Docs

Ctrl + K
Go to clerk.com

clerkMiddleware()

The clerkMiddleware() helper integrates Clerk authentication into your Next.js application through Middleware. clerkMiddleware() is compatible with both the App and Pages routers.

Configure clerkMiddleware()

Create a middleware.ts file at the root of your project, or in your src/ directory if you have one.

For more information about Middleware in Next.js, see the Next.js documentation(opens in a new tab).

middleware.ts
import { clerkMiddleware } from '@clerk/nextjs/server'; export default clerkMiddleware() export const config = { matcher: [ '/((?!.*\\..*|_next).*)', // Don't run middleware on static files '/', // Run middleware on index page '/(api|trpc)(.*)'], // Run middleware on API routes };

By default, clerkMiddleware will not protect any routes. All routes are public and you must opt-in to protection for routes.

createRouteMatcher()

createRouteMatcher() is a Clerk helper function that allows you to protect multiple routes. createRouteMatcher() accepts an array of routes and checks if the route the user is trying to visit matches one of the routes passed to it. The paths provided to this helper can be in the same format as the paths provided to the Next Middleware matcher.

The createRouteMatcher() helper returns a function that, if called with the req object from the Middleware, will return true if the user is trying to access a route that matches one of the routes passed to createRouteMatcher().

In the following example, createRouteMatcher() sets all /dashboard and /forum routes as protected routes.

const isProtectedRoute = createRouteMatcher([ '/dashboard(.*)', '/forum(.*)', ]);

Protect routes

You can protect routes by checking either or both of the following:

Protect routes based on user authentication status

You can protect routes based on user authentication status by checking if the user is signed in.

There are two methods that you can use:

  • Use auth().protect() if you want to redirect unauthenticated users to the sign-in route automatically.
  • Use auth().userId if you want more control over what your app does based on user authentication status.
middleware.ts
import { clerkMiddleware, createRouteMatcher } from '@clerk/nextjs/server'; const isProtectedRoute = createRouteMatcher([ '/dashboard(.*)', '/forum(.*)', ]); export default clerkMiddleware((auth, req) => { if (isProtectedRoute(req)) auth().protect(); }); export const config = { matcher: ['/((?!.*\\..*|_next).*)', '/', '/(api|trpc)(.*)'], };
app/middleware.ts
import { clerkMiddleware, createRouteMatcher } from '@clerk/nextjs/server'; const isProtectedRoute = createRouteMatcher([ '/dashboard(.*)', '/forum(.*)', ]); export default clerkMiddleware((auth, req) => { if (!auth().userId && isProtectedRoute(req)) { // Add custom logic to run before redirecting return auth().redirectToSignIn(); } }); export const config = { matcher: ['/((?!.+\\.[\\w]+$|_next).*)', '/', '/(api|trpc)(.*)']};

Protect routes based on user authorization status

You can protect routes based on user authorization status by checking if the user has the required roles or permissions.

There are two methods that you can use:

  • Use auth().protect() if you want Clerk to return a 404 if the user does not have the role or permission.
  • Use auth().has() if you want more control over what your app does based on the authorization status.
middleware.ts
import { clerkMiddleware, createRouteMatcher } from '@clerk/nextjs/server'; const isProtectedRoute = createRouteMatcher([ '/admin(.*)', ]); export default clerkMiddleware((auth, req) => { // Restrict admin routes to users with specific permissions if (isProtectedRoute(req)) { auth().protect(has => { return ( has({ permission: 'org:sys_memberships:manage' }) || has({ permission: 'org:sys_domains_manage' }) ) }) } }); export const config = { matcher: ['/((?!.*\\..*|_next).*)', '/', '/(api|trpc)(.*)'], };
middleware.ts
import { clerkMiddleware, createRouteMatcher } from '@clerk/nextjs/server'; const isProtectedRoute = createRouteMatcher([ '/admin(.*)', ]); export default clerkMiddleware((auth, req) => { // Restrict admin routes to users with specific permissions if (isProtectedRoute(req) && !auth().has({ permission: 'org:sys_memberships:manage' }) || !auth().has({ permission: 'org:sys_domains_manage' }) ){ // Add logic to run if the user does not have the required permissions return auth.redirectToSignIn(); } }); export const config = { matcher: ['/((?!.*\\..*|_next).*)', '/', '/(api|trpc)(.*)'], };

Protect multiple groups of routes

You can use more than one createRouteMatcher() in your application if you have two or more groups of routes.

The following example uses the has() method from Clerk's auth() helper.

middleware.ts
import { clerkMiddleware, createRouteMatcher } from '@clerk/nextjs/server'; const isTenantRoute = createRouteMatcher([ '/organization-selector', '/orgid/(.*)' ]) const isTenantAdminRoute = createRouteMatcher([ '/orgId/(.*)/memberships', '/orgId/(.*)/domain', ]); export default clerkMiddleware((auth, req) => { // Restrict admin routes to users with specific permissions if (isTenantAdminRoute(req)) { auth().protect(has => { return ( has({ permission: 'org:sys_memberships:manage' }) || has({ permission: 'org:sys_domains_manage' }) ) }) } // restrict organiztion routes to signed in users if (isTenantRoute(req)) auth().protect(); }); export const config = { matcher: ['/((?!.*\\..*|_next).*)', '/', '/(api|trpc)(.*)'], };

Debug your Middleware

If you are having issues getting your Middleware dialed in, or are trying to narrow down auth-related issues, you can use the debugging feature in clerkMiddlware(). Add { debug: true } to clerkMiddleware() and you will get debug logs in your terminal.

middleware.ts
import { clerkMiddleware } from '@clerk/nextjs/server'; export default clerkMiddleware((auth, req) => { // Add your middleware checks }, { debug: true }) export const config = { matcher: ['/((?!.*\\..*|_next).*)', '/', '/(api|trpc)(.*)'], };

If you would like to set up debugging for your development environment only, you can use the process.env.NODE_ENV variable to conditionally enable debugging. For example, { debug: process.env.NODE_ENV === 'development' }.

Combine Middleware

You can combine other Middleware with Clerk's Middleware by returning the second Middleware from clerkMiddleware().

middleware.ts
import { clerkMiddleware, createRouteMatcher, redirectToSignIn, } from '@clerk/nextjs/server'; import createMiddleware from 'next-intl/middleware'; import { AppConfig } from './utils/AppConfig'; const intlMiddleware = createMiddleware({ locales: AppConfig.locales, localePrefix: AppConfig.localePrefix, defaultLocale: AppConfig.defaultLocale, }); const isProtectedRoute = createRouteMatcher([ 'dashboard/(.*)', ]); export default clerkMiddleware((auth, req) => { if (isProtectedRoute(req)) auth().protect(); return intlMiddleware(req); }); export const config = { matcher: ['/((?!.+\\.[\\w]+$|_next).*)', '/', '/(api|trpc)(.*)'], };

clerkMiddleware() options

The clerkMiddleware() function accepts an optional object. The following options are available:

NameTypeDescription
audience?string | string[]A string or list of audiences(opens in a new tab). If passed, it is checked against the aud claim in the token.
authorizedParties?string[]An allowlist of origins to verify against, to protect your application from the subdomain cookie leaking attack.
For example: ['http://localhost:3000', 'https://example.com']
For more information, refer to the reference guide.
clockSkewInMs?numberSpecifies the allowed time difference (in milliseconds) between the Clerk server (which generates the token) and the clock of the user's application server when validating a token. Defaults to 5000 ms (5 seconds).
domain?stringThe domain used for satellites to inform Clerk where this application is deployed.
isSatellite?booleanWhen using Clerk's satellite feature, this should be set to true for secondary domains.
jwtKey?stringAn optional custom JWT key to use for session token validation.
proxyUrl?stringSpecify the URL of the proxy, if using a proxy.
signInUrl?stringAn alternative sign in URL.
publishableKeystringThe Clerk publishable key for your instance. This can be found in your Clerk Dashboard on the API Keys(opens in a new tab) page.
secretKey?stringThe Clerk secret key for your instance. This can be found in your Clerk Dashboard on the API Keys(opens in a new tab) page.

What did you think of this content?

Clerk © 2024