← 返回
未分类 Key

Sr Next Clerk Expert

Expert implementation of Clerk auth in Next.js 15/16+, enforcing route group protection, correct proxy.ts patterns, no auth() on public pages, and avoiding c...
熟练实现 Next.js 15/16+ 中的 Clerk 认证,强化路由组保护、正确的 proxy.ts 模式、公共页面不使用 auth(),并避免常见陷阱
michaelmonetized michaelmonetized 来源
未分类 clawhub v1.0.1 1 版本 100000 Key: 需要
★ 0
Stars
📥 197
下载
💾 0
安装
1
版本
#latest

概述

Senior Next.js + Clerk Expert

You are a senior engineer implementing Clerk authentication. Follow these patterns exactly—deviations cause production outages.


⚠️ CRITICAL: THE TWELVE COMMANDMENTS

These rules are non-negotiable. Violations cause 500 errors, infinite redirects, and broken sites.

#CommandmentViolation Consequence
--------------------------------------
IUse app/(private)/ route groupsMaintenance hell, broken auth
IIKeep proxy.ts simple (protect only private)Every new page needs proxy update
IIINEVER call auth() on public pages500 errors, slow pages, SEO death
IVUse / for conditional contentServer errors on static pages
VWrap Clerk components in Flash of wrong content
VIPair with Jarring loading states
VIIConfigure redirects in ClerkProviderRedirect loops
VIIINo handshake redirects on public pagesBroken user experience
IXKeep marketing pages STATICSlow pages, bad SEO
XVerify env vars EXACTLY (copy-paste only)Cryptic 500 errors
XIUse proxy.ts not middleware.ts (Next.js 16+)Deprecation warnings
XIITest as anonymous user before deployShip broken auth

Quick Reference

Project Structure

app/
├── (private)/           # Protected - requires auth
│   ├── dashboard/
│   ├── settings/
│   └── layout.tsx       # Can call auth() here
├── page.tsx             # PUBLIC - NO auth()
├── layout.tsx           # Root - ClerkProvider
├── sign-in/[[...sign-in]]/page.tsx
└── sign-up/[[...sign-up]]/page.tsx

The ONLY Correct proxy.ts

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

const isPrivateRoute = createRouteMatcher(["/(private)(.*)"]);

export default clerkMiddleware(async (auth, request) => {
  if (isPrivateRoute(request)) {
    await auth.protect();
  }
});

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)(.*)",
  ],
};

Patterns by Use Case

Public Page with Auth-Conditional Content

// app/page.tsx - CORRECT
import { ClerkLoaded, ClerkLoading, SignedIn, SignedOut } from "@clerk/nextjs";

export default function HomePage() {
  return (
    <main>
      <h1>Welcome</h1>
      <ClerkLoading>
        <Skeleton />
      </ClerkLoading>
      <ClerkLoaded>
        <SignedOut>
          <a href="/sign-in">Sign In</a>
        </SignedOut>
        <SignedIn>
          <a href="/dashboard">Dashboard</a>
        </SignedIn>
      </ClerkLoaded>
    </main>
  );
}

Private Layout (Route Protection)

// app/(private)/layout.tsx
import { auth } from "@clerk/nextjs/server";
import { redirect } from "next/navigation";

export default async function PrivateLayout({ children }: { children: React.ReactNode }) {
  const { userId } = await auth();
  if (!userId) redirect("/sign-in");
  return <>{children}</>;
}

Root Layout with ClerkProvider

// app/layout.tsx
import { ClerkProvider } from "@clerk/nextjs";

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <ClerkProvider
      signInUrl="/sign-in"
      signUpUrl="/sign-up"
      afterSignInUrl="/dashboard"
      afterSignUpUrl="/dashboard"
    >
      <html lang="en">
        <body>{children}</body>
      </html>
    </ClerkProvider>
  );
}

Advanced Patterns

For complex integrations, see reference files:


Environment Variables

# .env.local - COPY FROM CLERK DASHBOARD (do not type manually)
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_test_...
CLERK_SECRET_KEY=sk_test_...

# Optional redirects
NEXT_PUBLIC_CLERK_SIGN_IN_URL=/sign-in
NEXT_PUBLIC_CLERK_SIGN_UP_URL=/sign-up
NEXT_PUBLIC_CLERK_AFTER_SIGN_IN_URL=/dashboard
NEXT_PUBLIC_CLERK_AFTER_SIGN_UP_URL=/dashboard

⚠️ CRITICAL: Copy-paste keys from Clerk dashboard. Manual typing causes 1/l and x/X errors that produce cryptic 500s.


Common Errors & Fixes

ErrorCauseFix
-------------------
MIDDLEWARE_INVOCATION_FAILEDMissing/wrong CLERK_SECRET_KEYRe-copy from dashboard
?__clerk_handshake= in URLauth() called on public pageRemove auth(), use SignedIn/SignedOut
Infinite redirect loopMissing/wrong redirect configSet afterSignInUrl in ClerkProvider
500 on homepageServer-side auth on static pageMake page client-side or remove auth
Flash of wrong contentMissing ClerkLoaded wrapperWrap Clerk components

Anti-Patterns (NEVER DO)

// ❌ WRONG - auth() on public page
export default async function HomePage() {
  const { userId } = await auth();  // BREAKS STATIC RENDERING
  if (userId) redirect("/dashboard");
  return <LandingPage />;
}

// ❌ WRONG - listing every public route
const isPublicRoute = createRouteMatcher([
  "/", "/about", "/pricing", "/blog", "/contact", // MAINTENANCE HELL
]);

// ❌ WRONG - no ClerkLoaded wrapper
<SignedIn>
  <UserButton />  // FLASHES INCORRECTLY
</SignedIn>

// ❌ WRONG - middleware.ts in Next.js 16+
// File: middleware.ts  // DEPRECATED - USE proxy.ts

Migration: middleware.ts → proxy.ts

# Option 1: Rename
mv middleware.ts proxy.ts

# Option 2: Codemod
npx @next/codemod@latest middleware-to-proxy

🔐 Security Best Practices

Secret Management

  • Store secrets in platform env vars (Vercel, Railway, etc.) — never in code or git
  • Use separate keys for dev/staging/prod — Clerk provides different instances
  • Rotate keys if compromised — Clerk Dashboard → API Keys → Add new key → update env → delete old
  • Limit access — only team members who need keys should have dashboard access

Key Rotation Procedure

  1. Create new key in Clerk Dashboard
  2. Update production env var (Vercel: vercel env rm CLERK_SECRET_KEY production && vercel env add CLERK_SECRET_KEY production)
  3. Redeploy
  4. Verify auth works
  5. Delete old key from Clerk Dashboard

Webhook Security

  • Always verify signatures — use svix library (shown in references/webhooks.md)
  • Use HTTPS endpoints only — never expose webhook URLs over HTTP
  • Store CLERK_WEBHOOK_SECRET securely — same as other secrets

Debug Logging

⚠️ NEVER use debug mode in production:

// ❌ REMOVE BEFORE DEPLOYING
export default clerkMiddleware(
  async (auth, request) => { /* ... */ },
  { debug: true }  // LEAKS TOKENS TO LOGS
);

Debug mode logs handshake tokens (?__clerk_handshake=) which are sensitive. Use only in local development.

Least Privilege

SecretScopeNotes
----------------------
CLERK_SECRET_KEYServer onlyNever expose to client
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEYClient safeCan be in client bundles
CLERK_WEBHOOK_SECRETServer onlyWebhook handler only
STRIPE_SECRET_KEYServer onlyAPI routes only

Verification Checklist

Before deploying, verify:

  • [ ] proxy.ts exists (not middleware.ts)
  • [ ] proxy.ts ONLY protects /(private) routes
  • [ ] No auth() calls in app/page.tsx or marketing pages
  • [ ] All Clerk components wrapped in
  • [ ] shows skeleton/spinner
  • [ ] Env vars copied exactly from Clerk dashboard
  • [ ] Anonymous user can access homepage (incognito test)
  • [ ] Sign-in redirects to correct page
  • [ ] Dashboard requires authentication

版本历史

共 1 个版本

  • v1.0.1 当前
    2026-05-12 05:44 安全 安全

安全检测

腾讯云安全 (Keen)

安全,无风险
查看报告

腾讯云安全 (Sanbu)

安全,无风险
查看报告

🔗 相关推荐

dev-programming

CodeConductor.ai

larsonreever
AI驱动平台,提供快速全栈开发、智能体、工作流自动化及低代码AI集成的可扩展产品创建。
★ 75 📥 182,275
dev-programming

Github

steipete
使用 `gh` CLI 与 GitHub 交互,通过 `gh issue`、`gh pr`、`gh run` 和 `gh api` 管理议题、PR、CI 运行及高级查询。
★ 681 📥 328,865
design-media

Frontend Design

michaelmonetized
创建独特、高品质的生产级前端界面。用于构建Web组件、页面或应用程序。生成创意、精致的代码,避免通用的AI美学风格。
★ 88 📥 27,626