Clerk logo

Clerk Docs

Ctrl + K
Go to clerkstage.dev

Middleware

authMiddleware

We have launched a new version of the middleware that is compatible with both the stable version of next.js (with /pages) and the App Router (with /app).

Copy this snippet into a file named middleware.js or middleware.ts in your project root.

middleware.ts
1
import { authMiddleware } from "@clerk/nextjs";
2
3
export default authMiddleware();
4
5
export const config = {
6
matcher: ["/((?!.*\\..*|_next).*)", "/", "/(api|trpc)(.*)"],
7
};

Execution order of beforeAuth, publicRoutes and afterAuth

If you define an afterAuth function, it will run even if the request corresponds to a private route and no user is signed out.

If you don’t define an afterAuth, a redirect response to the signInUrl will be returned automatically.

This is a diagram that explains how and when the two handlers are invoked in the runtime.

Using afterAuth for fine grain control

Some developers will need to handle specific cases such as detecting if the user is inside an organization, or handle redirects differently. You can do that by using afterAuth

1
import { redirectToSignIn } from '@clerk/nextjs';
2
3
export default authMiddleware({
4
afterAuth(auth, req, evt) {
5
// handle users who aren't authenticated
6
if (!auth.userId && !auth.isPublicRoute) {
7
return redirectToSignIn({ returnBackUrl: req.url });
8
}
9
}
10
// redirect them to organization selection page
11
if(auth.userId && !auth.orgId && req.nextUrl.pathname !== "/org-selection"){
12
const orgSelection = new URL('/org-selection', req.url)
13
return NextResponse.redirect(orgSelection)
14
}
15
},
16
});

Chaining Middleware together

If you need to chain middleware's together you can do so by using the beforeAuth if you need it to happen before Clerk. Below is an example of Clerk & next-intl.

middleware.ts
1
import { authMiddleware } from "@clerk/nextjs";
2
3
import createMiddleware from "next-intl/middleware";
4
5
const intlMiddleware = createMiddleware({
6
locales: ["en", "el"],
7
8
defaultLocale: "en",
9
});
10
11
export default authMiddleware({
12
beforeAuth: (req) => {
13
return intlMiddleware(req);
14
},
15
16
publicRoutes: ["/", "/:locale/sign-in"],
17
});
18
19
export const config = {
20
matcher: ["/((?!.*\\..*|_next).*)", "/", "/(api|trpc)(.*)"],
21
};
22

Making pages public using publicRoutes

Below is an example of using `publicRoutes` to handle pages that should be accessible to users when they are not logged in.

1
import { authMiddleware } from "@clerk/nextjs";
2
export default authMiddleware({
3
publicRoutes: ["/"]
4
});
5
6
export const config = {
7
matcher: ["/((?!.*\\..*|_next).*)", "/", "/(api|trpc)(.*)"],
8
};

If you are building your own sign in pages, you don't need to add them to your publicRoutes. You can add them to your `.env`

1
NEXT_PUBLIC_CLERK_SIGN_IN_URL=/sign-in
2
NEXT_PUBLIC_CLERK_SIGN_UP_URL=/sign-up
3
NEXT_PUBLIC_CLERK_AFTER_SIGN_IN_URL=/
4
NEXT_PUBLIC_CLERK_AFTER_SIGN_UP_URL=/

Middleware argument types

Previous versions

withClerkMiddleware

This is our previous version of middleware and will soon be deprecated.

Copy this snippet into a file named middleware.js or middleware.ts in your project root.

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).*)',};
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).*)',};
11
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).*)',};

Clerk only depends on the withClerkMiddleware() wrapper. You are welcome to customize the internal middleware function as needed.

Before Next.js 12.2

Using the withEdgeMiddlewareAuth wrapper you can access authentication data

1
import { withEdgeMiddlewareAuth } from "@clerk/nextjs/edge-middleware";
2
3
export default withEdgeMiddlewareAuth(async req => {
4
const { userId, sessionId, getToken } = req.auth;
5
const supabaseToken = await getToken({ template: 'supabase' })
6
// Run your middleware
7
8
// Complete response
9
return NextResponse.next();
10
});
1
import { withEdgeMiddlewareAuth } from '@clerk/nextjs/edge-middleware'
2
import { NextResponse, NextRequest } from 'next/server'
3
import { ServerGetToken } from '@clerk/types'
4
5
//example usage of interfaces with Clerk
6
interface ClerkRequest extends NextRequest {
7
auth: {
8
userId?: string | null
9
sessionId?: string | null
10
getToken: ServerGetToken
11
}
12
}
13
14
export default withEdgeMiddlewareAuth(async (req: ClerkRequest) => {
15
const { userId, sessionId, getToken } = req.auth
16
const supabaseToken = await getToken({ template: 'supabase' })
17
// Load any data your application needs for the API route
18
return NextResponse.next();
19
})

Example Response

{
sessionId: 'sess_2GaMqUCB3Sc1WNAkWuNzsnYVVEy',
userId: 'user_2F2u1wtUyUlxKgFkKqtJNtpJJWj',
orgId: null,
getToken: [AsyncFunction (anonymous)],
claims: {
azp: 'http://localhost:3000',
exp: 1666622607,
iat: 1666622547,
iss: 'https://clerk.quiet.muskox-85.lcl.dev',
nbf: 1666622537,
sid: 'sess_2GaMqUCB3Sc1WNAkWuNzsnYVVEy',
sub: 'user_2F2u1wtUyUlxKgFkKqtJNtpJJWj'
}
}

More detailed information about the fields in this object can be found in the Authentication Object documentation.

Was this helpful?

Clerk © 2023