gocallum/nextjs16-agent-skills9 files

Clerk Nextjs Skills

Clerk authentication for Next.js 16 (App Router only) with proxy.ts setup, migration from middleware.ts, environment configuration, and MCP server integration.

Specification
Skill ID
gocallum/nextjs16-agent-skills/clerk-nextjs-skills
Publisher
gocallum
Repository
nextjs16-agent-skills
Installs
0
Files
9
Synced
Sep 23, 2026
How to use it

Open any RiverX project, open the Skills panel in the chat, and search for this identifier. The files are fetched from the source repository at install time.

gocallum/nextjs16-agent-skills/clerk-nextjs-skillsInstalls these files
  • CREATION_SUMMARY.md
  • QUICK_REFERENCE.md
  • README.md
  • SKILL.md
  • references/CLERK_ENV_SETUP.md
  • references/CLERK_MCP_SERVER_SETUP.md
  • references/EXAMPLES.md
  • references/PROXY_MIGRATION.md
  • scripts/setup-clerk-nextjs.sh

What this skill tells the agent

Links

Quick Start

1. Install Dependencies (Using pnpm)

pnpm add @clerk/nextjs
# For MCP server integration, also install:
pnpm add @vercel/mcp-adapter @clerk/mcp-tools

2. Create proxy.ts (Next.js 16)

The proxy.ts file replaces middleware.ts from Next.js 15. Create it at the root or in /src:

// proxy.ts (or src/proxy.ts)
import { clerkMiddleware } from '@clerk/nextjs/server'

export default clerkMiddleware()

export const config = {
  matcher: [
    '/((?!_next|[^?]*\\.(?:html?|css|js(?!on)|jpe?g|webp|png|gif|svg|ttf|woff2?|ico|csv|docx?|xlsx?|zip|webmanifest)).*)',
    '/(api|trpc)(.*)',
  ],
}

3. Set Environment Variables

Create .env.local in your project root:

NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=your_publishable_key_here
CLERK_SECRET_KEY=your_secret_key_here
NEXT_PUBLIC_CLERK_SIGN_IN_URL=/sign-in
NEXT_PUBLIC_CLERK_SIGN_UP_URL=/sign-up
NEXT_PUBLIC_CLERK_AFTER_SIGN_IN_URL=/
NEXT_PUBLIC_CLERK_AFTER_SIGN_UP_URL=/

4. Add ClerkProvider to Layout

// app/layout.tsx
import {
  ClerkProvider,
  SignInButton,
  SignUpButton,
  SignedIn,
  SignedOut,
  UserButton,
} from '@clerk/nextjs'
import type { Metadata } from 'next'

export const metadata: Metadata = {
  title: 'My App',
}

export default function RootLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
    <ClerkProvider>
      <html lang="en">
        <body>
          <header className="flex justify-end items-center p-4 gap-4 h-16">
            <SignedOut>
              <SignInButton />
              <SignUpButton />
            </SignedOut>
            <SignedIn>
              <UserButton />
            </SignedIn>
          </header>
          {children}
        </body>
      </html>
    </ClerkProvider>
  )
}

5. Run Your App

pnpm dev

Visit http://localhost:3000 and click "Sign Up" to create your first user.

Key Concepts

proxy.ts vs middleware.ts

  • Next.js 16 (App Router): Use proxy.ts for Clerk middleware
  • Next.js ≤15: Use middleware.ts with identical code (filename only differs)
  • Clerk's clerkMiddleware() function is the same regardless of filename
  • The matcher configuration ensures proper route handling and performance

Protecting Routes

By default, clerkMiddleware() does not protect routes—all are public. Use auth.protect() to require authentication:

// Protect specific route
import { auth } from '@clerk/nextjs/server'

export default async function Page() {
  const { userId } = await auth()
  
  if (!userId) {
    // Redirect handled by clerkMiddleware
  }
  
  return <div>Protected content for {userId}</div>
}

Or protect all routes in proxy.ts:

import { clerkMiddleware } from '@clerk/nextjs/server'

export default clerkMiddleware(async (auth, req) => {
  await auth.protect()
})

Environment Variable Validation

Check for required Clerk keys before runtime:

// lib/clerk-config.ts
export function validateClerkEnv() {
  const required = [
    'NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY',
    'CLERK_SECRET_KEY',
  ]
  
  const missing = required.filter(key => !process.env[key])
  
  if (missing.length > 0) {
    throw new Error(`Missing required Clerk environment variables: ${missing.join(', ')}`)
  }
}

Accessing User Data

Use Clerk hooks in client components:

// app/components/user-profile.tsx
'use client'

import { useUser } from '@clerk/nextjs'

export function UserProfile() {
  const { user, isLoaded } = useUser()
  
  if (!isLoaded) return <div>Loading...</div>
  
  if (!user) return <div>Not signed in</div>
  
  return (
    <div>
      <h1>{user.fullName}</h1>
      <p>{user.primaryEmailAddress?.emailAddress}</p>
    </div>
  )
}

Or in server components/actions:

// app/actions.ts
'use server'

import { auth, clerkClient } from '@clerk/nextjs/server'

export async function getUserData() {
  const { userId } = await auth()
  
  if (!userId) {
    throw new Error('Unauthorized')
  }
  
  const clerk = await clerkClient()
  const user = await clerk.users.getUser(userId)
  
  return user
}

Migrating from middleware.ts (Next.js 15) to proxy.ts (Next.js 16)

Step-by-Step Migration

  1. Rename the file from middleware.ts to proxy.ts (location remains same: root or /src)
  1. Keep the code identical - No functional changes needed: ```typescript // Before (middleware.ts) import { clerkMiddleware } from '@clerk/nextjs/server' export default clerkMiddleware() export const config = { ... }

// After (proxy.ts) - Same code import { clerkMiddleware } from '@clerk/nextjs/server' export default clerkMiddleware() export const config = { ... }


3. **Update Next.js version**:

pnpm add next@latest


4. **Verify environment variables** are still in `.env.local` (no changes needed)

5. **Test the migration**:

pnpm dev


### Troubleshooting Migration

- If routes aren't protected, ensure `proxy.ts` is in the correct location (root or `/src`)
- Check that `.env.local` has all required Clerk keys
- Clear `.next` cache if middleware changes don't take effect: `rm -rf .next && pnpm dev`
- Verify Next.js version is 16.0+: `pnpm list next`

## Building an MCP Server with Clerk

See [CLERK_MCP_SERVER_SETUP.md](references/CLERK_MCP_SERVER_SETUP.md) for complete MCP server integration.

### Quick MCP Setup Summary

1. **Install MCP dependencies**:

pnpm add @vercel/mcp-adapter @clerk/mcp-tools


2. **Create MCP route** at `app/[transport]/route.ts`:

import { verifyClerkToken } from '@clerk/mcp-tools/next' import { createMcpHandler, withMcpAuth } from '@vercel/mcp-adapter' import { auth, clerkClient } from '@clerk/nextjs/server'

const clerk = await clerkClient()

const handler = createMcpHandler((server) => { server.tool( 'get-clerk-user-data', 'Gets data about the Clerk user that authorized this request', {}, async (_, { authInfo }) => { const userId = authInfo!.extra!.userId! as string const userData = await clerk.users.getUser(userId) return { content: [{ type: 'text', text: JSON.stringify(userData) }], } }, ) })

const authHandler = withMcpAuth( handler, async (_, token) => { const clerkAuth = await auth({ acceptsToken: 'oauth_token' }) return verifyClerkToken(clerkAuth, token) }, { required: true, resourceMetadataPath: '/.well-known/oauth-protected-resource/mcp', }, )

export { authHandler as GET, authHandler as POST }


3. **Expose OAuth metadata endpoints** (see references for complete setup)

4. **Update proxy.ts** to exclude `.well-known` endpoints:

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

const isPublicRoute = createRouteMatcher([ '/.well-known/oauth-authorization-server(.*)',

Use this skill in a project

Open any RiverX project, search the Skills panel for gocallum/nextjs16-agent-skills/clerk-nextjs-skills, and install it in one click.

Use this skill