Force multi-factor authentication (MFA) for all users
By default, Clerk does not enforce multi-factor authentication (MFA) for all users. This guide demonstrates how to force MFA for all users by using clerkMiddleware()
to intercept all requests and check whether a user has MFA enabled. If the user does not have MFA enabled, clerkMiddleware()
redirects them to the /mfa
page where they can set up MFA.
Enable MFA in the Clerk Dashboard
If you haven't already, enable MFA for your users.
- In the Clerk Dashboard, navigate to the Multi-factor page.
- Toggle on the MFA strategies you would like to enable.
Customize the session token to include the two_factor_enabled
property
Every User
object has a two_factor_enabled
property that indicates whether the user has MFA enabled. Store this property in the session token so that you can check it in your clerkMiddleware()
.
- In the Clerk Dashboard, navigate to the Sessions page.
- In the Customize session token section, select Edit.
- In the modal that opens, add a key-value pair to the
Claims
object. The key can be any string, but the value must be theuser.two_factor_enabled
property, as shown in the following example.
{
"isMfa": "{{user.two_factor_enabled}}"
}
Update clerkMiddleware()
Update your clerkMiddleware()
to check if the user has MFA enabled.
import { clerkMiddleware, createRouteMatcher } from '@clerk/nextjs/server'
import { NextResponse } from 'next/server'
const isMFARoute = createRouteMatcher(['/account/manage-mfa/add(.*)'])
const isSignInRoute = createRouteMatcher(['/sign-in(.*)'])
export default clerkMiddleware(async (auth, req) => {
const { userId, sessionClaims } = await auth()
// Redirect to homepage if the user is signed in and on the sign-in page
if (userId !== null && isSignInRoute(req)) {
return NextResponse.redirect(new URL('/', req.url))
}
// Redirect to MFA setup page if MFA is not enabled
if (userId !== null && !isMFARoute(req)) {
if (sessionClaims.isMfa === undefined) {
console.error('You need to add the `isMfa` claim to your session token.')
}
if (sessionClaims.isMfa === false) {
return NextResponse.redirect(new URL('/account/manage-mfa/add', req.url))
}
}
})
export const config = {
matcher: [
// Skip Next.js internals and all static files, unless found in search params
'/((?!_next|[^?]*\\.(?:html?|css|js(?!on)|jpe?g|webp|png|gif|svg|ttf|woff2?|ico|csv|docx?|xlsx?|zip|webmanifest)).*)',
// Always run for API routes
'/(api|trpc)(.*)',
],
}
import { clerkMiddleware, createRouteMatcher } from '@clerk/astro/server'
const isMFARoute = createRouteMatcher(['/account/manage-mfa/add(.*)'])
const isSignInRoute = createRouteMatcher(['/sign-in(.*)'])
export const onRequest = clerkMiddleware((auth, context) => {
const { userId, sessionClaims } = auth()
// Redirect to homepage if the user is signed in and on the sign-in page
if (userId !== null && isSignInRoute(context.request)) {
return Response.redirect(new URL('/', context.request.url))
}
// Redirect to MFA setup page if MFA is not enabled
if (userId !== null && !isMFARoute(context.request)) {
if (sessionClaims.isMfa === undefined) {
console.error('You need to add the `isMfa` claim to your session token.')
}
if (sessionClaims.isMfa === false) {
return Response.redirect(new URL('/account/manage-mfa/add', context.request.url))
}
}
})
export const config = {
matcher: [
// Skip Next.js internals and all static files, unless found in search params
'/((?!_next|[^?]*\\.(?:html?|css|js(?!on)|jpe?g|webp|png|gif|svg|ttf|woff2?|ico|csv|docx?|xlsx?|zip|webmanifest)).*)',
// Always run for API routes
'/(api|trpc)(.*)',
],
}
By default, the Nuxt SDK automatically adds the clerkMiddleware()
helper to your Nuxt application. To manually configure the middleware, in your nuxt.config.ts
file, under the clerk
property, set skipServerMiddleware: true
.
export default defineNuxtConfig({
modules: ['@clerk/nuxt'],
clerk: {
skipServerMiddleware: true,
},
})
Then, in your server/middleware/clerk.ts
file, add the following code:
import { clerkMiddleware } from '@clerk/nuxt/server'
export default clerkMiddleware(async (event) => {
const isMFARoute = event.path.startsWith('/account/manage-mfa/add')
const isSignInRoute = event.path.startsWith('/sign-in')
const { userId, sessionClaims } = event.context.auth
// Redirect to homepage if the user is signed in and on the sign-in page
if (userId !== null && isSignInRoute) {
throw createError({
statusMessage: 'You are already signed in.',
})
}
// Redirect to MFA setup page if MFA is not enabled
if (userId !== null && !isMFARoute) {
if (sessionClaims.isMfa === undefined) {
throw createError({
statusMessage: 'You need to add the `isMfa` claim to your session token.',
})
}
if (sessionClaims.isMfa === false) {
throw createError({
statusMessage: 'You need to enable MFA for your account.',
})
}
}
})
export const config = {
matcher: [
// Skip Next.js internals and all static files, unless found in search params
'/((?!_next|[^?]*\\.(?:html?|css|js(?!on)|jpe?g|webp|png|gif|svg|ttf|woff2?|ico|csv|docx?|xlsx?|zip|webmanifest)).*)',
// Always run for API routes
'/(api|trpc)(.*)',
],
}
Build your MFA setup page
Follow the custom flow guide to build the /account/manage-mfa/add
page.
Feedback
Last updated on