clerkMiddleware()
| Next.js
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.
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.
Protect routes
You can protect routes by checking either or both of the following:
- User authentication status (user is signed in or out)
- User authorization status (user has the required role or permission)
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.
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 a404
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.
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 the auth()
helper.
Protect all routes
To protect all routes in your application and define specific routes as public, you can use any of the above methods and simply invert the if
condition.
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 clerkMiddleware()
. Add { debug: true }
to clerkMiddleware()
and you will get debug logs in your terminal.
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()
.
clerkMiddleware()
options
The clerkMiddleware()
function accepts an optional object. The following options are available:
- Name
audience?
- Type
string | string[]
- Description
A string or list of audiences. If passed, it is checked against the
aud
claim in the token.
- Name
authorizedParties?
- Type
string[]
- Description
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']
- Name
clockSkewInMs?
- Type
number
- Description
Specifies 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).
- Name
domain?
- Type
string
- Description
The domain used for satellites to inform Clerk where this application is deployed.
- Name
isSatellite?
- Type
boolean
- Description
When using Clerk's satellite feature, this should be set to
true
for secondary domains.
- Name
jwtKey
- Type
string
- Description
Used to verify the session token in a networkless manner. Supply the PEM public key from the API keys page -> Show JWT public key -> PEM Public Key section in the Clerk Dashboard. It's recommended to use the environment variable instead. For more information, refer to Manual JWT verification.
- Name
organizationSyncOptions?
- Type
OrganizationSyncOptions | undefined
- Description
Used to activate a specific organization or personal account based on URL path parameters. If there's a mismatch between the active organization in the session (e.g., as reported by
auth()
) and the organization indicated by the URL, the middleware will attempt to activate the organization specified in the URL.
- Name
proxyUrl?
- Type
string
- Description
Specify the URL of the proxy, if using a proxy.
- Name
signInUrl?
- Type
string
- Description
An alternative sign in URL.
- Name
signUpUrl?
- Type
string
- Description
An alternative sign up URL.
- Name
publishableKey
- Type
string
- Description
The Clerk Publishable Key for your instance. This can be found on the API keys page in the Clerk Dashboard.
- Name
secretKey?
- Type
string
- Description
The Clerk Secret Key for your instance. This can be found on the API keys page in the Clerk Dashboard. The
CLERK_ENCRYPTION_KEY
environment variable must be set when providingsecretKey
as an option, refer to Dynamic keys.
It's also possible to dynamically set options based on the incoming request:
The following options, known as "Dynamic Keys," are shared to the Next.js application server through clerkMiddleware
, enabling access by server-side helpers like auth()
:
signUpUrl
signInUrl
secretKey
publishableKey
Dynamic keys are encrypted and shared during request time using a AES encryption algorithm. When providing a secretKey
, the CLERK_ENCRYPTION_KEY
environment variable is mandatory and used as the encryption key. If no secretKey
is provided to clerkMiddleware
, the encryption key defaults to CLERK_SECRET_KEY
.
When providing CLERK_ENCRYPTION_KEY
, it is recommended to use a 32-byte (256-bit), pseudorandom value. You can use openssl
to generate a key:
For multi-tenant applications, you can dynamically define Clerk keys depending on the incoming request. Here's an example:
OrganizationSyncOptions
The organizationSyncOptions
property on the clerkMiddleware()
options
object has the type OrganizationSyncOptions
, which has the following properties:
- Name
organizationPatterns
- Type
Pattern[]
- Description
Specifies URL patterns that are organization-specific, containing an organization ID or slug as a path parameter. If a request matches this path, the organization identifier will be used to set that org as active.
If the route also matches the
personalAccountPatterns
prop, this prop takes precedence.Patterns must have a path parameter named either
:id
(to match a Clerk organization ID) or:slug
(to match a Clerk organization slug).Common examples:
["/orgs/:slug", "/orgs/:slug/(.*)"]
["/orgs/:id", "/orgs/:id/(.*)"]
["/app/:any/orgs/:slug", "/app/:any/orgs/:slug/(.*)"]
- Name
personalAccountPatterns
- Type
Pattern[]
- Description
URL patterns for resources that exist within the context of a Clerk Personal Account (user-specific, outside any organization).
If the route also matches the
organizationPattern
prop, theorganizationPattern
prop takes precedence.Common examples:
["/me", "/me/(.*)"]
["/user/:any", "/user/:any/(.*)"]
Pattern
A Pattern
is a string
that represents the structure of a URL path. In addition to any valid URL, it may include:
- Named path parameters prefixed with a colon (e.g.,
:id
,:slug
,:any
). - Wildcard token,
(.*)
, which matches the remainder of the path.
Examples
/orgs/:slug
URL | Matches | :slug value |
---|---|---|
/orgs/acmecorp | ✅ | acmecorp |
/orgs | ❌ | n/a |
/orgs/acmecorp/settings | ❌ | n/a |
/app/:any/orgs/:id
URL | Matches | :id value |
---|---|---|
/app/petstore/orgs/org_123 | ✅ | org_123 |
/app/dogstore/v2/orgs/org_123 | ❌ | n/a |
/personal-account/(.*)
URL | Matches |
---|---|
/personal-account/settings | ✅ |
/personal-account | ❌ |
Feedback
Last updated on