Clerk + Next.js Integration Security

Share

To secure Clerk + Next.js integration, you need to: (1) configure middleware with proper route matchers and explicit public routes, (2) use auth() in Server Components and API routes to verify users, (3) always use the verified userId for database operations, (4) add webhook routes to publicRoutes to allow Clerk callbacks, and (5) never trust client-provided user IDs. This blueprint ensures middleware protection and server-side verification work together.

Setup Time1-2 hours

TL;DR

Clerk's middleware handles route protection automatically. Use auth() in Server Components, currentUser() when you need full user data, and configure publicRoutes properly. The userId from auth() is verified server-side-use it for database queries.

Middleware Configuration Clerk Next.js

middleware.ts
import { clerkMiddleware, createRouteMatcher } from '@clerk/nextjs/server'

const isPublicRoute = createRouteMatcher([
  '/',
  '/about',
  '/blog(.*)',
  '/api/webhooks(.*)',
])

export default clerkMiddleware((auth, req) => {
  if (!isPublicRoute(req)) {
    auth().protect()
  }
})

export const config = {
  matcher: ['/((?!.*\\..*|_next).*)', '/', '/(api|trpc)(.*)'],
}

Protected Server Component

app/dashboard/page.tsx
import { auth, currentUser } from '@clerk/nextjs/server'
import { redirect } from 'next/navigation'

export default async function Dashboard() {
  const { userId } = auth()

  if (!userId) {
    redirect('/sign-in')
  }

  // Use userId for database queries
  const posts = await db.posts.findMany({
    where: { authorId: userId },
  })

  const user = await currentUser()

  return (
    <div>
      <h1>Welcome, {user?.firstName}</h1>
      {posts.map(post => <div key={post.id}>{post.title}</div>)}
    </div>
  )
}

Protected API Route

app/api/posts/route.ts
import { auth } from '@clerk/nextjs/server'
import { NextResponse } from 'next/server'

export async function POST(req: Request) {
  const { userId } = auth()

  if (!userId) {
    return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
  }

  const body = await req.json()

  const post = await db.posts.create({
    data: {
      title: body.title,
      authorId: userId,  // Verified Clerk user ID
    },
  })

  return NextResponse.json(post)
}

Middleware protects routes, not data. Always verify userId in API routes and Server Components. Use the verified userId for all database operations, never client-provided IDs.

Security Checklist

Pre-Launch Checklist

Middleware configured with correct matchers

Public routes explicitly defined

API routes check auth()

Database queries use verified userId

Webhook routes in publicRoutes

Auth0 + Next.js Alternative NextAuth + Prisma Self-Hosted OAuth Security Patterns

Check Your Clerk Integration

Scan for authentication security issues.

Start Free Scan
Security Blueprints

Clerk + Next.js Integration Security