Update to Vercel
Snapshot Oct 6, 2026 · 18:03 UTC · version 0.54.1
Collection source: downloaded plugin package. These snapshots do not have a confirmed matching collection source. Differences in file lists alone do not establish changes to the package.
Instructions updated for auth
Instruction wording changed from “Descope, and Auth0 setup for Next.js applications. Covers middleware auth patterns, sign-in/sign-up flows, and Marketplace provisioning. Use when implementing user authentication.” to “Better Auth, Descope, and Auth0 setup for Next.js applications, plus Sign in with Vercel, Vercel Passport, and Vercel KMS. Covers server config, route handlers, proxy.ts auth patterns, sign-in/sign-up flows, and Marketplace provisioning....”. 262 additional added or edited lines are in the evidence.
Observed in instructions or declared skills. Runtime behavior has not been tested.
Product description
Descope, and Auth0 setup for Next.js applications. Covers middleware auth patterns, sign-in/sign-up flows, and Marketplace provisioning. Use when implementing user authentication.
Better Auth, Descope, and Auth0 setup for Next.js applications, plus Sign in with Vercel, Vercel Passport, and Vercel KMS. Covers server config, route handlers, proxy.ts auth patterns, sign-in/sign-up flows, and Marketplace provisioning....
Skill instructions
Descope, and Auth0 setup for Next.js applications. Covers middleware auth patterns, sign-in/sign-up flows, and Marketplace provisioning. Use when implementing user authentication. - "https://nextjs.org/docs/app/building-your-applicat...
Better Auth, Descope, and Auth0 setup for Next.js applications, plus Sign in with Vercel, Vercel Passport, and Vercel KMS. Covers server config, route handlers, proxy.ts auth patterns, sign-in/sign-up flows, and Marketplace provisioning....
Compare saved observations
Download comparison JSONFull technical diff · 2 changed fields
changed /description
"Authentication integration guidance — Clerk (native Vercel Marketplace), Descope, and Auth0 setup for Next.js applications. Covers middleware auth patterns, sign-in/sign-up flows, and Marketplace provisioning. Use when implementing user authentication."
"Authentication integration guidance — Clerk (native Vercel Marketplace), Better Auth, Descope, and Auth0 setup for Next.js applications, plus Sign in with Vercel, Vercel Passport, and Vercel KMS. Covers server config, route handlers, proxy.ts auth patterns, sign-in/sign-up flows, and Marketplace provisioning. Use when implementing user authentication, sessions, protected routes, or protecting deployments."
changed /skill_md_contents
"---\nname: auth\ndescription: Authentication integration guidance — Clerk (native Vercel Marketplace), Descope, and Auth0 setup for Next.js applications. Covers middleware auth patterns, sign-in/sign-up flows, and Marketplace provisioning. Use when implementing user authentication.\nmetadata:\n priority: 6\n docs:\n - \"https://authjs.dev/getting-started\"\n - \"https://nextjs.org/docs/app/building-your-application/authentication\"\n sitemap: \"https://authjs.dev/sitemap.xml\"\n pathPatterns:\n - 'middleware.ts'\n - 'middleware.js'\n - 'src/middleware.ts'\n - 'src/middleware.js'\n - 'clerk.config.*'\n - 'app/sign-in/**'\n - 'app/sign-up/**'\n - 'src/app/sign-in/**'\n - 'src/app/sign-up/**'\n - 'app/(auth)/**'\n - 'src/app/(auth)/**'\n - 'auth.config.*'\n - 'auth.ts'\n - 'auth.js'\n bashPatterns:\n - '\\bnpm\\s+(install|i|add)\\s+[^\\n]*@clerk/nextjs\\b'\n - '\\bpnpm\\s+(install|i|add)\\s+[^\\n]*@clerk/nextjs\\b'\n - '\\bbun\\s+(install|i|add)\\s+[^\\n]*@clerk/nextjs\\b'\n - '\\byarn\\s+add\\s+[^\\n]*@clerk/nextjs\\b'\n - '\\bnpm\\s+(install|i|add)\\s+[^\\n]*@descope/nextjs-sdk\\b'\n - '\\bpnpm\\s+(install|i|add)\\s+[^\\n]*@descope/nextjs-sdk\\b'\n - '\\bbun\\s+(install|i|add)\\s+[^\\n]*@descope/nextjs-sdk\\b'\n - '\\byarn\\s+add\\s+[^\\n]*@descope/nextjs-sdk\\b'\n - '\\bnpm\\s+(install|i|add)\\s+[^\\n]*@auth0/nextjs-auth0\\b'\n - '\\bpnpm\\s+(install|i|add)\\s+[^\\n]*@auth0/nextjs-auth0\\b'\n - '\\bbun\\s+(install|i|add)\\s+[^\\n]*@auth0/nextjs-auth0\\b'\n - '\\byarn\\s+add\\s+[^\\n]*@auth0/nextjs-auth0\\b'\n---\n\n# Authentication Integrations\n\nYou are an expert in authentication for Vercel-deployed applications — covering Clerk (native Vercel Marketplace integration), Descope, and Auth0.\n\n## Clerk (Recommended — Native Marketplace Integration)\n\nClerk is a native Vercel Marketplace integration with auto-provisioned environment variables and unified billing. Current SDK: `@clerk/nextjs` v7 (Core 3, March 2026).\n\n### Install via Marketplace\n\n```bash\n# Install Clerk from Vercel Marketplace (auto-provisions env vars)\nvercel integration add clerk\n```\n\nAuto-provisioned environment variables:\n- `CLERK_SECRET_KEY` — server-side API key\n- `NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY` — client-side publishable key\n\n### SDK Setup\n\n```bash\n# Install the Clerk Next.js SDK\nnpm install @clerk/nextjs\n```\n\n### Middleware Configuration\n\n```ts\n// middleware.ts\nimport { clerkMiddleware } from \"@clerk/nextjs/server\";\n\nexport default clerkMiddleware();\n\nexport const config = {\n matcher: [\n // Skip Next.js internals and static files\n \"/((?!_next|[^?]*\\\\.(?:html?|css|js(?!on)|jpe?g|webp|png|gif|svg|ttf|woff2?|ico|csv|docx?|xlsx?|zip|webmanifest)).*)\",\n // Always run for API routes\n \"/(api|trpc)(.*)\",\n ],\n};\n```\n\n### Protect Routes\n\n```ts\n// middleware.ts — protect specific routes\nimport { clerkMiddleware, createRouteMatcher } from \"@clerk/nextjs/server\";\n\nconst isProtectedRoute = createRouteMatcher([\"/dashboard(.*)\", \"/api(.*)\"]);\n\nexport default clerkMiddleware(async (auth, req) => {\n if (isProtectedRoute(req)) {\n await auth.protect();\n }\n});\n```\n\n### Frontend API Proxy (Core 3)\n\nProxy Clerk's Frontend API through your own domain to avoid third-party requests:\n\n```ts\n// middleware.ts\nexport default clerkMiddleware({\n frontendApiProxy: { enabled: true },\n});\n```\n\n### Provider Setup\n\n```tsx\n// app/layout.tsx\nimport { ClerkProvider } from \"@clerk/nextjs\";\n\nexport default function RootLayout({\n children,\n}: {\n children: React.ReactNode;\n}) {\n return (\n <ClerkProvider>\n <html lang=\"en\">\n <body>{children}</body>\n </html>\n </ClerkProvider>\n );\n}\n```\n\n### Sign-In and Sign-Up Pages\n\n```tsx\n// app/sign-in/[[...sign-in]]/page.tsx\nimport { SignIn } from \"@clerk/nextjs\";\n\nexport default function Page() {\n return <SignIn />;\n}\n```\n\n```tsx\n// app/sign-up/[[...sign-up]]/page.tsx\nimport { SignUp } from \"@clerk/nextjs\";\n\nexport default function Page() {\n return <SignUp />;\n}\n```\n\nAdd routing env vars to `.env.local`:\n\n```env\nNEXT_PUBLIC_CLERK_SIGN_IN_URL=/sign-in\nNEXT_PUBLIC_CLERK_SIGN_UP_URL=/sign-up\n```\n\n### Access User Data\n\n```tsx\n// Server component\nimport { currentUser } from \"@clerk/nextjs/server\";\n\nexport default async function Page() {\n const user = await currentUser();\n return <p>Hello, {user?.firstName}</p>;\n}\n```\n\n```tsx\n// Client component\n\"use client\";\nimport { useUser } from \"@clerk/nextjs\";\n\nexport default function UserGreeting() {\n const { user, isLoaded } = useUser();\n if (!isLoaded) return null;\n return <p>Hello, {user?.firstName}</p>;\n}\n```\n\n### API Route Protection\n\n```ts\n// app/api/protected/route.ts\nimport { auth } from \"@clerk/nextjs/server\";\n\nexport async function GET() {\n const { userId } = await auth();\n if (!userId) {\n return Response.json({ error: \"Unauthorized\" }, { status: 401 });\n }\n return Response.json({ userId });\n}\n```\n\n## Descope\n\nDescope is available on the Vercel Marketplace with native integration support.\n\n### Install via Marketplace\n\n```bash\nvercel integration add descope\n```\n\n### SDK Setup\n\n```bash\nnpm install @descope/nextjs-sdk\n```\n\n### Provider and Middleware\n\n```tsx\n// app/layout.tsx\nimport { AuthProvider } from \"@descope/nextjs-sdk\";\n\nexport default function RootLayout({\n children,\n}: {\n children: React.ReactNode;\n}) {\n return (\n <AuthProvider projectId={process.env.NEXT_PUBLIC_DESCOPE_PROJECT_ID!}>\n <html lang=\"en\">\n <body>{children}</body>\n </html>\n </AuthProvider>\n );\n}\n```\n\n```ts\n// middleware.ts\nimport { authMiddleware } from \"@descope/nextjs-sdk/server\";\n\nexport default authMiddleware({\n projectId: process.env.DESCOPE_PROJECT_ID!,\n publicRoutes: [\"/\", \"/sign-in\"],\n});\n```\n\n### Sign-In Flow\n\n```tsx\n\"use client\";\nimport { Descope } from \"@descope/nextjs-sdk\";\n\nexport default function SignInPage() {\n return <Descope flowId=\"sign-up-or-in\" />;\n}\n```\n\n## Auth0\n\nAuth0 provides a mature authentication platform with extensive identity provider support.\n\n### SDK Setup\n\n```bash\nnpm install @auth0/nextjs-auth0\n```\n\n### Configuration\n\n```ts\n// lib/auth0.ts\nimport { Auth0Client } from \"@auth0/nextjs-auth0/server\";\n\nexport const auth0 = new Auth0Client();\n```\n\nRequired environment variables:\n\n```env\nAUTH0_SECRET=<random-secret>\nAUTH0_BASE_URL=http://localhost:3000\nAUTH0_ISSUER_BASE_URL=https://your-tenant.auth0.com\nAUTH0_CLIENT_ID=<client-id>\nAUTH0_CLIENT_SECRET=<client-secret>\n```\n\n### Middleware\n\n```ts\n// middleware.ts\nimport { auth0 } from \"@/lib/auth0\";\nimport { NextRequest, NextResponse } from \"next/server\";\n\nexport async function middleware(request: NextRequest) {\n return await auth0.middleware(request);\n}\n\nexport const config = {\n matcher: [\n \"/((?!_next/static|_next/image|favicon.ico|sitemap.xml|robots.txt).*)\",\n ],\n};\n```\n\n### Access Session Data\n\n```tsx\n// Server component\nimport { auth0 } from \"@/lib/auth0\";\n\nexport default async function Page() {\n const session = await auth0.getSession();\n return session ? (\n <p>Hello, {session.user.name}</p>\n ) : (\n <a href=\"/auth/login\">Log in</a>\n );\n}\n```\n\n## Decision Matrix\n\n| Need | Recommended | Why |\n|------|------------|-----|\n| Fastest setup on Vercel | Clerk | Native Marketplace, auto-provisioned env vars |\n| Passwordless / social login flows | Descope | Visual flow builder, Marketplace native |\n| Enterprise SSO / SAML / multi-tenant | Auth0 | Deep enterprise identity support |\n| Pre-built UI components | Clerk | Drop-in `<SignIn />`, `<UserButton />` |\n| Vercel unified billing | Clerk or Descope | Both are native Marketplace integrations |\n\n## Clerk Core 3 Breaking Changes (March 2026)\n\nClerk provides an upgrade CLI that scans your codebase and applies codemods: `npx @clerk/upgrade`. Requires **Node.js 20.9.0+**.\n\n- **`auth()` is async** — always use `const { userId } = await auth()`, not synchronous\n- **`auth.protect()` moved** — use `await auth.protect()` directly, not from the return value of `auth()`\n- **`clerkClient()` is async** — use `await clerkClient()` in middleware handlers\n- **`authMiddleware()` removed** — migrate to `clerkMiddleware()`\n- **`@clerk/types` deprecated** — import types from SDK subpath exports: `import type { UserResource } from '@clerk/react/types'` (works from any SDK package)\n- **`ClerkProvider` no longer forces dynamic rendering** — pass the `dynamic` prop if needed\n- **Cache components** — when using Next.js cache components, place `<ClerkProvider>` inside `<body>`, not wrapping `<html>`\n- **Satellite domains** — new `satelliteAutoSync` option skips handshake redirects when no session cookies exist\n- **Smaller bundles** — React is now shared across framework SDKs (~50KB gzipped savings)\n- **Better offline handling** — `getToken()` now correctly distinguishes signed-out from offline states\n\n## Cross-References\n\n- **Marketplace install and env var provisioning** → `⤳ skill: marketplace`\n- **Middleware routing patterns** → `⤳ skill: routing-middleware`\n- **Environment variable management** → `⤳ skill: env-vars`\n- **Vercel OAuth (Sign in with Vercel)** → `⤳ skill: sign-in-with-vercel`\n\n## Official Documentation\n\n- [Clerk + Vercel Marketplace](https://clerk.com/docs/deployments/vercel)\n- [Clerk Next.js Quickstart](https://clerk.com/docs/quickstarts/nextjs)\n- [Descope Next.js SDK](https://docs.descope.com/getting-started/nextjs)\n- [Auth0 Next.js SDK](https://auth0.com/docs/quickstart/webapp/nextjs)\n""---\nname: auth\ndescription: Authentication integration guidance — Clerk (native Vercel Marketplace), Better Auth, Descope, and Auth0 setup for Next.js applications, plus Sign in with Vercel, Vercel Passport, and Vercel KMS. Covers server config, route handlers, proxy.ts auth patterns, sign-in/sign-up flows, and Marketplace provisioning. Use when implementing user authentication, sessions, protected routes, or protecting deployments.\nmetadata:\n priority: 6\n docs:\n - \"https://authjs.dev/getting-started\"\n - \"https://nextjs.org/docs/app/guides/authentication\"\n - \"https://better-auth.com/llms.txt\"\n sitemap: \"https://authjs.dev/sitemap.xml\"\n pathPatterns:\n - 'proxy.ts'\n - 'proxy.js'\n - 'src/proxy.ts'\n - 'src/proxy.js'\n - 'middleware.ts'\n - 'middleware.js'\n - 'src/middleware.ts'\n - 'src/middleware.js'\n - 'clerk.config.*'\n - 'app/sign-in/**'\n - 'app/sign-up/**'\n - 'src/app/sign-in/**'\n - 'src/app/sign-up/**'\n - 'app/(auth)/**'\n - 'src/app/(auth)/**'\n - 'auth.config.*'\n - 'auth.ts'\n - 'auth.js'\n - 'lib/auth.ts'\n - 'src/lib/auth.ts'\n - 'lib/auth-client.ts'\n - 'src/lib/auth-client.ts'\n - 'app/api/auth/[...all]/**'\n - 'src/app/api/auth/[...all]/**'\n bashPatterns:\n - '\\bnpm\\s+(install|i|add)\\s+[^\\n]*@clerk/nextjs\\b'\n - '\\bpnpm\\s+(install|i|add)\\s+[^\\n]*@clerk/nextjs\\b'\n - '\\bbun\\s+(install|i|add)\\s+[^\\n]*@clerk/nextjs\\b'\n - '\\byarn\\s+add\\s+[^\\n]*@clerk/nextjs\\b'\n - '\\bnpm\\s+(install|i|add)\\s+[^\\n]*@descope/nextjs-sdk\\b'\n - '\\bpnpm\\s+(install|i|add)\\s+[^\\n]*@descope/nextjs-sdk\\b'\n - '\\bbun\\s+(install|i|add)\\s+[^\\n]*@descope/nextjs-sdk\\b'\n - '\\byarn\\s+add\\s+[^\\n]*@descope/nextjs-sdk\\b'\n - '\\bnpm\\s+(install|i|add)\\s+[^\\n]*@auth0/nextjs-auth0\\b'\n - '\\bpnpm\\s+(install|i|add)\\s+[^\\n]*@auth0/nextjs-auth0\\b'\n - '\\bbun\\s+(install|i|add)\\s+[^\\n]*@auth0/nextjs-auth0\\b'\n - '\\byarn\\s+add\\s+[^\\n]*@auth0/nextjs-auth0\\b'\n - '\\bnpm\\s+(install|i|add)\\s+[^\\n]*@vercel/kms\\b'\n - '\\bpnpm\\s+(install|i|add)\\s+[^\\n]*@vercel/kms\\b'\n - '\\bbun\\s+(install|i|add)\\s+[^\\n]*@vercel/kms\\b'\n - '\\byarn\\s+add\\s+[^\\n]*@vercel/kms\\b'\n - '\\bnpm\\s+(install|i|add)\\s+[^\\n]*\\bbetter-auth\\b'\n - '\\bpnpm\\s+(install|i|add)\\s+[^\\n]*\\bbetter-auth\\b'\n - '\\bbun\\s+(install|i|add)\\s+[^\\n]*\\bbetter-auth\\b'\n - '\\byarn\\s+add\\s+[^\\n]*\\bbetter-auth\\b'\n - '\\b(npx|bunx|pnpm\\s+dlx)\\s+(auth@latest|@better-auth/cli)\\b'\n importPatterns:\n - \"@vercel/kms\"\n - \"better-auth\"\nvalidate:\n -\n pattern: 'VERCEL_CLIENT_(ID|SECRET)|vercel\\.com/oauth/(authorize|access_token|token)'\n message: 'Hand-rolled Vercel OAuth detected. Use the Sign in with Vercel OIDC provider (or the built-in `vercel` social provider in Better Auth) instead of manual token exchange.'\n severity: recommended\n skipIfFileContains: 'signInWithVercel|@vercel/auth|better-auth|socialProviders'\nretrieval:\n aliases:\n - authentication\n - login system\n - sign in\n - auth flow\n - sign in with vercel\n - passport\n - kms\n intents:\n - add auth\n - protect routes\n - manage sessions\n - implement login\n - secure api endpoints\n entities:\n - NextAuth\n - Auth.js\n - Better Auth\n - betterAuth\n - authClient\n - JWT\n - OAuth\n - session\n - middleware\n - getServerSession\n - Vercel Passport\n - Okta\n - Microsoft Entra ID\n - Vercel KMS\n - signToken\n examples:\n - add login to my app\n - protect this route with auth\n - set up NextAuth\n - set up Better Auth\n - add better auth to my next app\nchainTo:\n -\n pattern: 'export\\s+(default\\s+)?function\\s+middleware'\n targetSkill: routing-middleware\n message: 'Auth logic in a middleware() export — Next.js 16 uses proxy.ts with a proxy() export. Loading Routing Middleware guidance for the migration.'\n -\n pattern: 'from\\s+[''\\\"](jsonwebtoken)[''\"]|require\\s*\\(\\s*[''\\\"](jsonwebtoken)[''\"]|jwt\\.sign\\s*\\('\n targetSkill: auth\n message: 'Manual JWT handling with jsonwebtoken detected — use Clerk, Better Auth, or Auth.js for built-in session handling, CSRF protection, and token rotation.'\n skipIfFileContains: 'better-auth|@clerk|next-auth'\n -\n pattern: 'from\\s+[''\\\"](next-auth)[''\"]|NextAuthOptions|authOptions\\s*:'\n targetSkill: auth\n message: 'Legacy next-auth (v4) pattern detected — loading auth guidance for Auth.js v5 migration with the new universal auth() helper.'\n -\n pattern: 'from\\s+[''\"]@clerk/nextjs[''\"]'\n targetSkill: auth\n message: 'Clerk import detected — loading Auth guidance for Clerk v7 patterns, middleware setup, organization handling, and Vercel Marketplace integration.'\n skipIfFileContains: 'clerkMiddleware|ClerkProvider'\n -\n pattern: \"bcrypt|argon2\"\n targetSkill: auth\n message: 'Manual password hashing detected (bcrypt/argon2) — use Clerk, Better Auth, or Auth0 for authentication with built-in password hashing and rate limiting.'\n skipIfFileContains: \"@clerk|@auth0|better-auth\"\n -\n pattern: 'from\\s+[''\"]better-auth[''\"]|betterAuth\\s*\\('\n targetSkill: auth\n message: 'Better Auth config detected — loading Auth guidance for the Next.js route handler, nextCookies plugin, cookie-only middleware checks, cookie cache, and Marketplace Postgres/Redis wiring.'\n skipIfFileContains: 'nextCookies|toNextJsHandler'\n---\n\n# Authentication Integrations\n\nYou are an expert in authentication for Vercel-deployed applications — covering Clerk (native Vercel Marketplace integration), Better Auth (self-hosted, with data in your own database), Descope, and Auth0 for application sign-in, plus Vercel's own primitives: Sign in with Vercel (OAuth/OIDC provider), Passport (deployment protection with your identity provider), and KMS (managed signing keys).\n\nAll Next.js examples target Next.js 16, where the request-interception file is `proxy.ts` (exporting `proxy`). On Next.js 15 or earlier the same code lives in `middleware.ts` (exporting `middleware`).\n\n## Clerk (Recommended — Native Marketplace Integration)\n\nClerk is a native Vercel Marketplace integration with auto-provisioned environment variables and unified billing. Current SDK: `@clerk/nextjs` v7 (Core 3, March 2026).\n\n### Install via Marketplace\n\n```bash\n# Install Clerk from Vercel Marketplace (auto-provisions env vars)\nvercel integration add clerk\n```\n\nAuto-provisioned environment variables:\n- `CLERK_SECRET_KEY` — server-side API key\n- `NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY` — client-side publishable key\n\n### SDK Setup\n\n```bash\n# Install the Clerk Next.js SDK\nnpm install @clerk/nextjs\n```\n\n### Proxy Configuration\n\n```ts\n// proxy.ts (Next.js 16; middleware.ts on Next.js 15 and earlier)\nimport { clerkMiddleware } from \"@clerk/nextjs/server\";\n\nexport default clerkMiddleware();\n\nexport const config = {\n matcher: [\n // Skip Next.js internals and static files\n \"/((?!_next|[^?]*\\\\.(?:html?|css|js(?!on)|jpe?g|webp|png|gif|svg|ttf|woff2?|ico|csv|docx?|xlsx?|zip|webmanifest)).*)\",\n // Always run for API routes\n \"/(api|trpc)(.*)\",\n ],\n};\n```\n\n### Protect Routes\n\n```ts\n// proxy.ts — protect specific routes\nimport { clerkMiddleware, createRouteMatcher } from \"@clerk/nextjs/server\";\n\nconst isProtectedRoute = createRouteMatcher([\"/dashboard(.*)\", \"/api(.*)\"]);\n\nexport default clerkMiddleware(async (auth, req) => {\n if (isProtectedRoute(req)) {\n await auth.protect();\n }\n});\n```\n\n### Frontend API Proxy (Core 3)\n\nProxy Clerk's Frontend API through your own domain to avoid third-party requests:\n\n```ts\n// proxy.ts\nexport default clerkMiddleware({\n frontendApiProxy: { enabled: true },\n});\n```\n\n### Provider Setup\n\n```tsx\n// app/layout.tsx\nimport { ClerkProvider } from \"@clerk/nextjs\";\n\nexport default function RootLayout({\n children,\n}: {\n children: React.ReactNode;\n}) {\n return (\n <html lang=\"en\">\n <body>\n <ClerkProvider>{children}</ClerkProvider>\n </body>\n </html>\n );\n}\n```\n\n### Sign-In and Sign-Up Pages\n\n```tsx\n// app/sign-in/[[...sign-in]]/page.tsx\nimport { SignIn } from \"@clerk/nextjs\";\n\nexport default function Page() {\n return <SignIn />;\n}\n```\n\n```tsx\n// app/sign-up/[[...sign-up]]/page.tsx\nimport { SignUp } from \"@clerk/nextjs\";\n\nexport default function Page() {\n return <SignUp />;\n}\n```\n\nAdd routing env vars to `.env.local`:\n\n```env\nNEXT_PUBLIC_CLERK_SIGN_IN_URL=/sign-in\nNEXT_PUBLIC_CLERK_SIGN_UP_URL=/sign-up\n```\n\n### Access User Data\n\n```tsx\n// Server component\nimport { currentUser } from \"@clerk/nextjs/server\";\n\nexport default async function Page() {\n const user = await currentUser();\n return <p>Hello, {user?.firstName}</p>;\n}\n```\n\n```tsx\n// Client component\n\"use client\";\nimport { useUser } from \"@clerk/nextjs\";\n\nexport default function UserGreeting() {\n const { user, isLoaded } = useUser();\n if (!isLoaded) return null;\n return <p>Hello, {user?.firstName}</p>;\n}\n```\n\n### API Route Protection\n\n```ts\n// app/api/protected/route.ts\nimport { auth } from \"@clerk/nextjs/server\";\n\nexport async function GET() {\n const { userId } = await auth();\n if (!userId) {\n return Response.json({ error: \"Unauthorized\" }, { status: 401 });\n }\n return Response.json({ userId });\n}\n```\n\n## Better Auth (Self-Hosted)\n\nBetter Auth is a framework-agnostic TypeScript auth library that runs inside your app. Users, sessions, and accounts live in your own database, so the only external dependency is the database itself. Choose it when the user wants auth inside their app with data in their own database, or is building on a framework other than Next.js. Current release line: v1.7.\n\n### Agent Workflow\n\n1. **Detect** framework (Next.js App/Pages Router, SvelteKit, Nuxt, Hono…), database/ORM (`prisma/schema.prisma`, `drizzle.config.ts`, `pg`, `@neondatabase/serverless`), and package manager from the lockfile.\n2. **Install** `better-auth` plus the DB driver. Provision Postgres from the Marketplace if the project has no database.\n3. **Create** `lib/auth.ts` (server) and `lib/auth-client.ts` (client).\n4. **Mount** the route handler at `app/api/auth/[...all]/route.ts`.\n5. **Migrate** with `npx auth@latest migrate` (built-in adapter) or `generate` + the ORM's migrate (Prisma/Drizzle).\n6. **Protect** routes: cookie check in `proxy.ts`, real `getSession()` in pages/route handlers.\n7. **Verify** `GET /api/auth/ok` returns `{ \"status\": \"ok\" }`, then run a sign-up → sign-in → `getSession()` pass.\n8. **Re-run migrate** after every plugin change.\n\n### Install\n\n```bash\nnpm install better-auth pg\n# Postgres from the Marketplace (auto-provisions DATABASE_URL)\nvercel integration add neon\n```\n\n### Environment Variables\n\n```env\nBETTER_AUTH_SECRET=<openssl rand -base64 32>\nBETTER_AUTH_URL=http://localhost:3000\n```\n\n- **Production:** set `BETTER_AUTH_URL` to your production domain.\n- **Preview:** leave `BETTER_AUTH_URL` unset for the Preview environment. Better Auth infers the base URL from the incoming request, so every preview URL works without config. `VERCEL_URL` is **not** read automatically.\n- OAuth providers need registered redirect URIs (`<base>/api/auth/callback/<provider>`), so social login on previews needs a stable branch alias.\n\n### Server Config\n\n```ts\n// lib/auth.ts\nimport { betterAuth } from \"better-auth\";\nimport { nextCookies } from \"better-auth/next-js\";\nimport { Pool } from \"pg\";\n\nexport const auth = betterAuth({\n database: new Pool({ connectionString: process.env.DATABASE_URL }),\n emailAndPassword: { enabled: true },\n socialProviders: {\n github: {\n clientId: process.env.GITHUB_CLIENT_ID!,\n clientSecret: process.env.GITHUB_CLIENT_SECRET!,\n },\n // Sign in with Vercel — create a Vercel App in the dashboard for credentials\n vercel: {\n clientId: process.env.VERCEL_CLIENT_ID!,\n clientSecret: process.env.VERCEL_CLIENT_SECRET!,\n },\n },\n session: {\n // Signed cookie cache: most getSession() calls skip the database\n cookieCache: { enabled: true, maxAge: 5 * 60 },\n },\n plugins: [nextCookies()], // keep last — sets cookies from Server Actions\n});\n```\n\nPrisma / Drizzle / MongoDB users pass an adapter instead of a pool: `prismaAdapter(prisma, { provider: \"postgresql\" })` from `better-auth/adapters/prisma`, `drizzleAdapter(db, { provider: \"pg\" })` from `better-auth/adapters/drizzle`.\n\n### Route Handler\n\n```ts\n// app/api/auth/[...all]/route.ts\nimport { auth } from \"@/lib/auth\";\nimport { toNextJsHandler } from \"better-auth/next-js\";\n\nexport const { GET, POST } = toNextJsHandler(auth);\n```\n\n### Database Schema\n\n```bash\nnpx auth@latest migrate # built-in adapter (pg / mysql / sqlite): applies directly\nnpx auth@latest generate # Prisma / Drizzle: writes the schema, then run your ORM's migrate\n```\n\nRe-run after adding or removing plugins. Verify with `GET /api/auth/ok` → `{ \"status\": \"ok\" }`.\n\n### Client\n\n```ts\n// lib/auth-client.ts\nimport { createAuthClient } from \"better-auth/react\";\n\nexport const authClient = createAuthClient();\n```\n\n```tsx\n\"use client\";\nimport { authClient } from \"@/lib/auth-client\";\n\n// Sign in\nawait authClient.signIn.email({ email, password, callbackURL: \"/dashboard\" });\nawait authClient.signIn.social({ provider: \"github\", callbackURL: \"/dashboard\" });\nawait authClient.signUp.email({ email, password, name });\nawait authClient.signOut();\n\n// Reactive session\nconst { data: session, isPending } = authClient.useSession();\n```\n\n### Access Session Data (Server)\n\n```tsx\n// Server Component, Server Action, or Route Handler\nimport { auth } from \"@/lib/auth\";\nimport { headers } from \"next/headers\";\nimport { redirect } from \"next/navigation\";\n\nexport default async function Page() {\n const session = await auth.api.getSession({ headers: await headers() });\n if (!session) redirect(\"/sign-in\");\n return <p>Hello, {session.user.name}</p>;\n}\n```\n\nEvery endpoint (including plugin endpoints) is callable server-side via `auth.api.*` — no HTTP round-trip.\n\n### Protect Routes\n\nOnly check for the session **cookie** in middleware/proxy — never call the database there. Do the real check in the page or route handler.\n\n```ts\n// proxy.ts (Next.js 16) — rename to middleware.ts on Next.js 15\nimport { NextRequest, NextResponse } from \"next/server\";\nimport { getSessionCookie } from \"better-auth/cookies\";\n\nexport function proxy(request: NextRequest) {\n if (!getSessionCookie(request)) {\n return NextResponse.redirect(new URL(\"/sign-in\", request.url));\n }\n return NextResponse.next();\n}\n\nexport const config = { matcher: [\"/dashboard/:path*\"] };\n```\n\n### Keep It Fast on Vercel\n\n- **Cookie cache on** (`session.cookieCache`) — avoids a DB read per request in Fluid Compute functions.\n- **Redis for shared state** — `vercel integration add upstash`, then pass a `secondaryStorage` adapter. Sessions and rate-limit counters move to Redis; the default in-memory rate limiter does not share state across function instances. Set `rateLimit.storage: \"secondary-storage\"`.\n- **Import plugins from subpaths** for tree-shaking: `import { twoFactor } from \"better-auth/plugins/two-factor\"`, not `\"better-auth/plugins\"`.\n- **Cookie check only in middleware** — `getSessionCookie()` is synchronous and works on the Edge runtime; `auth.api.getSession()` in middleware requires the Node.js runtime and costs a DB hit per request.\n- **Separate frontend origin?** Add it to `trustedOrigins` (wildcards allowed: `\"https://*.vercel.app\"`). Same-origin apps need nothing.\n\n### Common Mistakes\n\n| Symptom | Cause | Fix |\n|---------|-------|-----|\n| Cookies not set from a Server Action | `nextCookies()` missing or not last in `plugins` | Add it as the last plugin |\n| Middleware slow or fails on Edge | `auth.api.getSession()` in middleware | Use `getSessionCookie()`; verify in the page |\n| \"Invalid origin\" on a separate frontend | Origin not trusted | Add it to `trustedOrigins` |\n| Type errors or missing tables after adding a plugin | Schema not regenerated | Re-run `npx auth@latest migrate` / `generate` |\n| Adapter can't find a model | Config uses the DB table name | Use the ORM **model** name (`modelName: \"user\"`, not `\"users\"`) |\n| Rate limits reset per request in production | Default in-memory rate-limit storage | Use `secondaryStorage` (Redis) or `rateLimit.storage: \"database\"` |\n| Callback URL wrong on Vercel | `BETTER_AUTH_URL` points at localhost or a preview | Set the production domain in Production; leave unset for Preview |\n\n### Plugins\n\nServer plugin + matching client plugin + re-run migrations.\n\n| Feature | Server import | Client plugin |\n|---------|--------------|---------------|\n| Two-factor (TOTP/OTP) | `twoFactor` from `better-auth/plugins/two-factor` | `twoFactorClient` |\n| Organizations / teams | `organization` from `better-auth/plugins/organization` | `organizationClient` |\n| Magic link | `magicLink` from `better-auth/plugins/magic-link` | `magicLinkClient` |\n| Admin / user management | `admin` from `better-auth/plugins/admin` | `adminClient` |\n| Passkeys (WebAuthn) | `passkey` from `@better-auth/passkey` | `passkeyClient` |\n| Enterprise SSO (SAML/OIDC) | `sso` from `@better-auth/sso` | — |\n| Stripe subscriptions | `stripe` from `@better-auth/stripe` | `stripeClient` |\n| Third-party tokens via Vercel Connect | `genericOAuth` + `connect` from `@vercel/connect/betterauth` | — |\n\n### Agent Tooling\n\nInstall the official Better Auth skills for deeper, version-aware guidance (planning questionnaire, adapters, migrations, best practices):\n\n```bash\nnpx skills add better-auth/skills\n```\n\nDocs are versioned. Match the `better-auth` version in the lockfile, then start from [better-auth.com/llms.txt](https://better-auth.com/llms.txt) or the docs MCP server (`https://mcp.better-auth.com/mcp`, or `npx auth@latest mcp --cursor` to register it).\n\n## Descope\n\nDescope is available on the Vercel Marketplace with native integration support.\n\n### Install via Marketplace\n\n```bash\nvercel integration add descope\n```\n\n### SDK Setup\n\n```bash\nnpm install @descope/nextjs-sdk\n```\n\n### Provider and Proxy\n\n```tsx\n// app/layout.tsx\nimport { AuthProvider } from \"@descope/nextjs-sdk\";\n\nexport default function RootLayout({\n children,\n}: {\n children: React.ReactNode;\n}) {\n return (\n <AuthProvider projectId={process.env.NEXT_PUBLIC_DESCOPE_PROJECT_ID!}>\n <html lang=\"en\">\n <body>{children}</body>\n </html>\n </AuthProvider>\n );\n}\n```\n\n```ts\n// proxy.ts\nimport { authMiddleware } from \"@descope/nextjs-sdk/server\";\n\nexport default authMiddleware({\n projectId: process.env.DESCOPE_PROJECT_ID!,\n publicRoutes: [\"/\", \"/sign-in\"],\n});\n```\n\n### Sign-In Flow\n\n```tsx\n\"use client\";\nimport { Descope } from \"@descope/nextjs-sdk\";\n\nexport default function SignInPage() {\n return <Descope flowId=\"sign-up-or-in\" />;\n}\n```\n\n## Auth0\n\nAuth0 provides a mature authentication platform with extensive identity provider support.\n\n### SDK Setup\n\n```bash\nnpm install @auth0/nextjs-auth0\n```\n\n### Configuration\n\n```ts\n// lib/auth0.ts\nimport { Auth0Client } from \"@auth0/nextjs-auth0/server\";\n\nexport const auth0 = new Auth0Client();\n```\n\nRequired environment variables:\n\n```env\nAUTH0_SECRET=<random-secret>\nAPP_BASE_URL=http://localhost:3000 # optional: omit on Vercel previews and the SDK infers it from the request host\nAUTH0_DOMAIN=your-tenant.auth0.com\nAUTH0_CLIENT_ID=<client-id>\nAUTH0_CLIENT_SECRET=<client-secret>\n```\n\n### Proxy\n\n```ts\n// proxy.ts\nimport { auth0 } from \"@/lib/auth0\";\nimport type { NextRequest } from \"next/server\";\n\nexport async function proxy(request: NextRequest) {\n return await auth0.middleware(request);\n}\n\nexport const config = {\n matcher: [\n \"/((?!_next/static|_next/image|favicon.ico|sitemap.xml|robots.txt).*)\",\n ],\n};\n```\n\n### Access Session Data\n\n```tsx\n// Server component\nimport { auth0 } from \"@/lib/auth0\";\n\nexport default async function Page() {\n const session = await auth0.getSession();\n return session ? (\n <p>Hello, {session.user.name}</p>\n ) : (\n <a href=\"/auth/login\">Log in</a>\n );\n}\n```\n\n## Vercel-Native Identity Primitives\n\nThese are not replacements for Clerk, Descope, or Auth0. They cover cases where the identity comes from Vercel itself or where you need Vercel to hold the keys.\n\n### Sign in with Vercel\n\nLet users log in with their Vercel account. Vercel's Identity Provider implements OAuth 2.0 and OpenID Connect: register an App in the dashboard, redirect to `https://vercel.com/oauth/authorize` with PKCE (`code_challenge_method: 'S256'`), `state`, and `nonce`, then exchange the `code` at `https://api.vercel.com/login/oauth/token`. Access tokens last 1 hour; refresh tokens last 30 days and rotate on use. Never hand-roll the token exchange without PKCE, state, and nonce checks. Docs: https://vercel.com/docs/sign-in-with-vercel/getting-started\n\n### Vercel Passport (deployment protection)\n\nPassport protects whole deployments behind your own OIDC identity provider (Okta, Microsoft Entra ID, Auth0, or any OIDC-compatible provider). Vercel Connect stores the OAuth application configuration, and Vercel redirects unauthenticated visitors before any request reaches your code. Use it for internal tools and previews instead of application-level auth. Your app can read the verified visitor identity server-side or verify a forwarded Passport token as a JWT. Enterprise plan; GA since July 2026. Docs: https://vercel.com/docs/passport\n\n### Vercel KMS (managed signing keys)\n\nKMS signs JWTs and messages with keys that never leave Vercel. Create an issuer in the team's Key Management settings, install `@vercel/kms`, and call `signJWT({ issuerId, claims, ttl })` (resolves to `{ token, keyId, algorithm, fingerprint }`; `@vercel/kms` 0.3.0+, `signToken` is deprecated) inside a route handler or Server Component; the function's OIDC token authorizes the request automatically. Relying parties verify against the published JWKS at `https://kms.vercel.com/<issuerId>/jwks.json`. Use it instead of storing private signing keys in environment variables. Docs: https://vercel.com/docs/kms\n\n## Decision Matrix\n\n| Need | Recommended | Why |\n|------|------------|-----|\n| Fastest setup on Vercel | Clerk | Native Marketplace, auto-provisioned env vars |\n| Passwordless / social login flows | Descope | Visual flow builder, Marketplace native |\n| Enterprise SSO / SAML / multi-tenant | Auth0 | Deep enterprise identity support |\n| Pre-built UI components | Clerk | Drop-in `<SignIn />`, `<UserButton />` |\n| Vercel unified billing | Clerk or Descope | Both are native Marketplace integrations |\n| Auth in your own database, no hosted vendor | Better Auth | Runs in your app, data in your own database, no vendor dashboard to configure |\n| Not Next.js (SvelteKit, Nuxt, Hono, Expo, plain Node) | Better Auth | Framework-agnostic handler + client adapters |\n| Orgs, 2FA, passkeys, SSO, Stripe as code | Better Auth | Plugin system with generated schema |\n| \"Log in with Vercel\" for a developer tool | Sign in with Vercel | Vercel is the identity provider |\n| Restrict a deployment to employees behind Okta/Entra | Vercel Passport | Platform-level, no app code |\n| Sign JWTs without storing private keys | Vercel KMS | Managed keys, OIDC-authorized signing |\n\n## Clerk Core 3 Breaking Changes (March 2026)\n\nClerk provides an upgrade CLI that scans your codebase and applies codemods: `npx @clerk/upgrade`. Requires **Node.js 20.9.0+**.\n\n- **`SignedIn`/`SignedOut`/`Protect` replaced by `Show`** — e.g. `<Protect role=\"admin\">` → `<Show when={{ role: 'admin' }}>`\n- **Package renames** — `@clerk/clerk-react` → `@clerk/react`, `@clerk/clerk-expo` → `@clerk/expo`\n- **`ClerkProvider` must be inside `<body>`, not wrapping `<html>`** — the CLI handles this automatically\n- **`@clerk/types` removed** — import types from the SDK's own `/types` entry point, or `@clerk/shared/types` for framework-agnostic code\n- **Redirect props renamed** — `afterSignInUrl`/`afterSignUpUrl`/`redirectUrl` → `fallbackRedirectUrl`/`signUpFallbackRedirectUrl`/`forceRedirectUrl`\n- **Minimum Next.js version: 15.2.3** — Next.js 13 and 14 are no longer supported\n- **Satellite domains** — apps no longer auto-redirect on first visit; set `satelliteAutoSync: true` in middleware and `ClerkProvider` to restore Core 2 behavior\n- **`getToken()` throws `ClerkOfflineError` when offline** — previously returned `null`; still returns `null` when signed out\n\n## Cross-References\n\n- **Marketplace install and env var provisioning** → `⤳ skill: marketplace`\n- **Proxy and Routing Middleware patterns** → `⤳ skill: routing-middleware`\n- **Accessing protected deployments from CLI or tests** → `⤳ skill: access-protected-vercel-deployment`\n- **Environment variable management** → `⤳ skill: env-vars`\n- **Neon Postgres / Upstash Redis for Better Auth** → `⤳ skill: vercel-storage`\n- **Third-party OAuth tokens through Better Auth (`@vercel/connect/betterauth`)** → `⤳ skill: vercel-connect`\n\n## Official Documentation\n\n- [Better Auth Docs](https://better-auth.com/docs) · [Next.js integration](https://better-auth.com/docs/integrations/next) · [Sign in with Vercel](https://better-auth.com/docs/authentication/vercel)\n- [Better Auth agent skills](https://github.com/better-auth/skills)\n- [Clerk + Vercel Marketplace](https://clerk.com/docs/deployments/vercel)\n- [Clerk Next.js Quickstart](https://clerk.com/docs/quickstarts/nextjs)\n- [Descope Next.js SDK](https://docs.descope.com/getting-started/nextjs)\n- [Auth0 Next.js SDK](https://auth0.com/docs/quickstart/webapp/nextjs)\n- [Sign in with Vercel](https://vercel.com/docs/sign-in-with-vercel)\n- [Vercel Passport](https://vercel.com/docs/passport)\n- [Vercel KMS](https://vercel.com/docs/kms)\n"SKILL.md line diff
--- before +++ after @@ -1,13 +1,18 @@ --- name: auth -description: Authentication integration guidance — Clerk (native Vercel Marketplace), Descope, and Auth0 setup for Next.js applications. Covers middleware auth patterns, sign-in/sign-up flows, and Marketplace provisioning. Use when implementing user authentication. +description: Authentication integration guidance — Clerk (native Vercel Marketplace), Better Auth, Descope, and Auth0 setup for Next.js applications, plus Sign in with Vercel, Vercel Passport, and Vercel KMS. Covers server config, route handlers, proxy.ts auth patterns, sign-in/sign-up flows, and Marketplace provisioning. Use when implementing user authentication, sessions, protected routes, or protecting deployments. metadata: priority: 6 docs: - "https://authjs.dev/getting-started" - - "https://nextjs.org/docs/app/building-your-application/authentication" + - "https://nextjs.org/docs/app/guides/authentication" + - "https://better-auth.com/llms.txt" sitemap: "https://authjs.dev/sitemap.xml" pathPatterns: + - 'proxy.ts' + - 'proxy.js' + - 'src/proxy.ts' + - 'src/proxy.js' - 'middleware.ts' - 'middleware.js' - 'src/middleware.ts' @@ -22,6 +27,12 @@ - 'auth.config.*' - 'auth.ts' - 'auth.js' + - 'lib/auth.ts' + - 'src/lib/auth.ts' + - 'lib/auth-client.ts' + - 'src/lib/auth-client.ts' + - 'app/api/auth/[...all]/**' + - 'src/app/api/auth/[...all]/**' bashPatterns: - '\bnpm\s+(install|i|add)\s+[^\n]*@clerk/nextjs\b' - '\bpnpm\s+(install|i|add)\s+[^\n]*@clerk/nextjs\b' @@ -35,11 +46,97 @@ - '\bpnpm\s+(install|i|add)\s+[^\n]*@auth0/nextjs-auth0\b' - '\bbun\s+(install|i|add)\s+[^\n]*@auth0/nextjs-auth0\b' - '\byarn\s+add\s+[^\n]*@auth0/nextjs-auth0\b' + - '\bnpm\s+(install|i|add)\s+[^\n]*@vercel/kms\b' + - '\bpnpm\s+(install|i|add)\s+[^\n]*@vercel/kms\b' + - '\bbun\s+(install|i|add)\s+[^\n]*@vercel/kms\b' + - '\byarn\s+add\s+[^\n]*@vercel/kms\b' + - '\bnpm\s+(install|i|add)\s+[^\n]*\bbetter-auth\b' + - '\bpnpm\s+(install|i|add)\s+[^\n]*\bbetter-auth\b' + - '\bbun\s+(install|i|add)\s+[^\n]*\bbetter-auth\b' + - '\byarn\s+add\s+[^\n]*\bbetter-auth\b' + - '\b(npx|bunx|pnpm\s+dlx)\s+(auth@latest|@better-auth/cli)\b' + importPatterns: + - "@vercel/kms" + - "better-auth" +validate: + - + pattern: 'VERCEL_CLIENT_(ID|SECRET)|vercel\.com/oauth/(authorize|access_token|token)' + message: 'Hand-rolled Vercel OAuth detected. Use the Sign in with Vercel OIDC provider (or the built-in `vercel` social provider in Better Auth) instead of manual token exchange.' + severity: recommended + skipIfFileContains: 'signInWithVercel|@vercel/auth|better-auth|socialProviders' +retrieval: + aliases: + - authentication + - login system + - sign in + - auth flow + - sign in with vercel + - passport + - kms + intents: + - add auth + - protect routes + - manage sessions + - implement login + - secure api endpoints + entities: + - NextAuth + - Auth.js + - Better Auth + - betterAuth + - authClient + - JWT + - OAuth + - session + - middleware + - getServerSession + - Vercel Passport + - Okta + - Microsoft Entra ID + - Vercel KMS + - signToken + examples: + - add login to my app + - protect this route with auth + - set up NextAuth + - set up Better Auth + - add better auth to my next app +chainTo: + - + pattern: 'export\s+(default\s+)?function\s+middleware' + targetSkill: routing-middleware + message: 'Auth logic in a middleware() export — Next.js 16 uses proxy.ts with a proxy() export. Loading Routing Middleware guidance for the migration.' + - + pattern: 'from\s+[''\"](jsonwebtoken)[''"]|require\s*\(\s*[''\"](jsonwebtoken)[''"]|jwt\.sign\s*\(' + targetSkill: auth + message: 'Manual JWT handling with jsonwebtoken detected — use Clerk, Better Auth, or Auth.js for built-in session handling, CSRF protection, and token rotation.' + skipIfFileContains: 'better-auth|@clerk|next-auth' + - + pattern: 'from\s+[''\"](next-auth)[''"]|NextAuthOptions|authOptions\s*:' + targetSkill: auth + message: 'Legacy next-auth (v4) pattern detected — loading auth guidance for Auth.js v5 migration with the new universal auth() helper.' + - + pattern: 'from\s+[''"]@clerk/nextjs[''"]' + targetSkill: auth + message: 'Clerk import detected — loading Auth guidance for Clerk v7 patterns, middleware setup, organization handling, and Vercel Marketplace integration.' + skipIfFileContains: 'clerkMiddleware|ClerkProvider' + - + pattern: "bcrypt|argon2" + targetSkill: auth + message: 'Manual password hashing detected (bcrypt/argon2) — use Clerk, Better Auth, or Auth0 for authentication with built-in password hashing and rate limiting.' + skipIfFileContains: "@clerk|@auth0|better-auth" + - + pattern: 'from\s+[''"]better-auth[''"]|betterAuth\s*\(' + targetSkill: auth + message: 'Better Auth config detected — loading Auth guidance for the Next.js route handler, nextCookies plugin, cookie-only middleware checks, cookie cache, and Marketplace Postgres/Redis wiring.' + skipIfFileContains: 'nextCookies|toNextJsHandler' --- # Authentication Integrations -You are an expert in authentication for Vercel-deployed applications — covering Clerk (native Vercel Marketplace integration), Descope, and Auth0. +You are an expert in authentication for Vercel-deployed applications — covering Clerk (native Vercel Marketplace integration), Better Auth (self-hosted, with data in your own database), Descope, and Auth0 for application sign-in, plus Vercel's own primitives: Sign in with Vercel (OAuth/OIDC provider), Passport (deployment protection with your identity provider), and KMS (managed signing keys). + +All Next.js examples target Next.js 16, where the request-interception file is `proxy.ts` (exporting `proxy`). On Next.js 15 or earlier the same code lives in `middleware.ts` (exporting `middleware`). ## Clerk (Recommended — Native Marketplace Integration) @@ -63,10 +160,10 @@ npm install @clerk/nextjs ``` -### Middleware Configuration +### Proxy Configuration ```ts -// middleware.ts +// proxy.ts (Next.js 16; middleware.ts on Next.js 15 and earlier) import { clerkMiddleware } from "@clerk/nextjs/server"; export default clerkMiddleware(); @@ -84,7 +181,7 @@ ### Protect Routes ```ts -// middleware.ts — protect specific routes +// proxy.ts — protect specific routes import { clerkMiddleware, createRouteMatcher } from "@clerk/nextjs/server"; const isProtectedRoute = createRouteMatcher(["/dashboard(.*)", "/api(.*)"]); @@ -101,7 +198,7 @@ Proxy Clerk's Frontend API through your own domain to avoid third-party requests: ```ts -// middleware.ts +// proxy.ts export default clerkMiddleware({ frontendApiProxy: { enabled: true }, }); @@ -119,11 +216,11 @@ children: React.ReactNode; }) { return ( - <ClerkProvider> - <html lang="en"> - <body>{children}</body> - </html> - </ClerkProvider> + <html lang="en"> + <body> + <ClerkProvider>{children}</ClerkProvider> + </body> + </html> ); } ``` @@ -194,6 +291,195 @@ } ``` +## Better Auth (Self-Hosted) + +Better Auth is a framework-agnostic TypeScript auth library that runs inside your app. Users, sessions, and accounts live in your own database, so the only external dependency is the database itself. Choose it when the user wants auth inside their app with data in their own database, or is building on a framework other than Next.js. Current release line: v1.7. + +### Agent Workflow + +1. **Detect** framework (Next.js App/Pages Router, SvelteKit, Nuxt, Hono…), database/ORM (`prisma/schema.prisma`, `drizzle.config.ts`, `pg`, `@neondatabase/serverless`), and package manager from the lockfile. +2. **Install** `better-auth` plus the DB driver. Provision Postgres from the Marketplace if the project has no database. +3. **Create** `lib/auth.ts` (server) and `lib/auth-client.ts` (client). +4. **Mount** the route handler at `app/api/auth/[...all]/route.ts`. +5. **Migrate** with `npx auth@latest migrate` (built-in adapter) or `generate` + the ORM's migrate (Prisma/Drizzle). +6. **Protect** routes: cookie check in `proxy.ts`, real `getSession()` in pages/route handlers. +7. **Verify** `GET /api/auth/ok` returns `{ "status": "ok" }`, then run a sign-up → sign-in → `getSession()` pass. +8. **Re-run migrate** after every plugin change. + +### Install + +```bash +npm install better-auth pg +# Postgres from the Marketplace (auto-provisions DATABASE_URL) +vercel integration add neon +``` + +### Environment Variables + +```env +BETTER_AUTH_SECRET=<openssl rand -base64 32> +BETTER_AUTH_URL=http://localhost:3000 +``` + +- **Production:** set `BETTER_AUTH_URL` to your production domain. +- **Preview:** leave `BETTER_AUTH_URL` unset for the Preview environment. Better Auth infers the base URL from the incoming request, so every preview URL works without config. `VERCEL_URL` is **not** read automatically. +- OAuth providers need registered redirect URIs (`<base>/api/auth/callback/<provider>`), so social login on previews needs a stable branch alias. + +### Server Config + +```ts +// lib/auth.ts +import { betterAuth } from "better-auth"; +import { nextCookies } from "better-auth/next-js"; +import { Pool } from "pg"; + +export const auth = betterAuth({ + database: new Pool({ connectionString: process.env.DATABASE_URL }), + emailAndPassword: { enabled: true }, + socialProviders: { + github: { + clientId: process.env.GITHUB_CLIENT_ID!, + clientSecret: process.env.GITHUB_CLIENT_SECRET!, + }, + // Sign in with Vercel — create a Vercel App in the dashboard for credentials + vercel: { + clientId: process.env.VERCEL_CLIENT_ID!, + clientSecret: process.env.VERCEL_CLIENT_SECRET!, + }, + }, + session: { + // Signed cookie cache: most getSession() calls skip the database + cookieCache: { enabled: true, maxAge: 5 * 60 }, + }, + plugins: [nextCookies()], // keep last — sets cookies from Server Actions +}); +``` + +Prisma / Drizzle / MongoDB users pass an adapter instead of a pool: `prismaAdapter(prisma, { provider: "postgresql" })` from `better-auth/adapters/prisma`, `drizzleAdapter(db, { provider: "pg" })` from `better-auth/adapters/drizzle`. + +### Route Handler + +```ts +// app/api/auth/[...all]/route.ts +import { auth } from "@/lib/auth"; +import { toNextJsHandler } from "better-auth/next-js"; + +export const { GET, POST } = toNextJsHandler(auth); +``` + +### Database Schema + +```bash +npx auth@latest migrate # built-in adapter (pg / mysql / sqlite): applies directly +npx auth@latest generate # Prisma / Drizzle: writes the schema, then run your ORM's migrate +``` + +Re-run after adding or removing plugins. Verify with `GET /api/auth/ok` → `{ "status": "ok" }`. + +### Client + +```ts +// lib/auth-client.ts +import { createAuthClient } from "better-auth/react"; + +export const authClient = createAuthClient(); +``` + +```tsx +"use client"; +import { authClient } from "@/lib/auth-client"; + +// Sign in +await authClient.signIn.email({ email, password, callbackURL: "/dashboard" }); +await authClient.signIn.social({ provider: "github", callbackURL: "/dashboard" }); +await authClient.signUp.email({ email, password, name }); +await authClient.signOut(); + +// Reactive session +const { data: session, isPending } = authClient.useSession(); +``` + +### Access Session Data (Server) + +```tsx +// Server Component, Server Action, or Route Handler +import { auth } from "@/lib/auth"; +import { headers } from "next/headers"; +import { redirect } from "next/navigation"; + +export default async function Page() { + const session = await auth.api.getSession({ headers: await headers() }); + if (!session) redirect("/sign-in"); + return <p>Hello, {session.user.name}</p>; +} +``` + +Every endpoint (including plugin endpoints) is callable server-side via `auth.api.*` — no HTTP round-trip. + +### Protect Routes + +Only check for the session **cookie** in middleware/proxy — never call the database there. Do the real check in the page or route handler. + +```ts +// proxy.ts (Next.js 16) — rename to middleware.ts on Next.js 15 +import { NextRequest, NextResponse } from "next/server"; +import { getSessionCookie } from "better-auth/cookies"; + +export function proxy(request: NextRequest) { + if (!getSessionCookie(request)) { + return NextResponse.redirect(new URL("/sign-in", request.url)); + } + return NextResponse.next(); +} + +export const config = { matcher: ["/dashboard/:path*"] }; +``` + +### Keep It Fast on Vercel + +- **Cookie cache on** (`session.cookieCache`) — avoids a DB read per request in Fluid Compute functions. +- **Redis for shared state** — `vercel integration add upstash`, then pass a `secondaryStorage` adapter. Sessions and rate-limit counters move to Redis; the default in-memory rate limiter does not share state across function instances. Set `rateLimit.storage: "secondary-storage"`. +- **Import plugins from subpaths** for tree-shaking: `import { twoFactor } from "better-auth/plugins/two-factor"`, not `"better-auth/plugins"`. +- **Cookie check only in middleware** — `getSessionCookie()` is synchronous and works on the Edge runtime; `auth.api.getSession()` in middleware requires the Node.js runtime and costs a DB hit per request. +- **Separate frontend origin?** Add it to `trustedOrigins` (wildcards allowed: `"https://*.vercel.app"`). Same-origin apps need nothing. + +### Common Mistakes + +| Symptom | Cause | Fix | +|---------|-------|-----| +| Cookies not set from a Server Action | `nextCookies()` missing or not last in `plugins` | Add it as the last plugin | +| Middleware slow or fails on Edge | `auth.api.getSession()` in middleware | Use `getSessionCookie()`; verify in the page | +| "Invalid origin" on a separate frontend | Origin not trusted | Add it to `trustedOrigins` | +| Type errors or missing tables after adding a plugin | Schema not regenerated | Re-run `npx auth@latest migrate` / `generate` | +| Adapter can't find a model | Config uses the DB table name | Use the ORM **model** name (`modelName: "user"`, not `"users"`) | +| Rate limits reset per request in production | Default in-memory rate-limit storage | Use `secondaryStorage` (Redis) or `rateLimit.storage: "database"` | +| Callback URL wrong on Vercel | `BETTER_AUTH_URL` points at localhost or a preview | Set the production domain in Production; leave unset for Preview | + +### Plugins + +Server plugin + matching client plugin + re-run migrations. + +| Feature | Server import | Client plugin | +|---------|--------------|---------------| +| Two-factor (TOTP/OTP) | `twoFactor` from `better-auth/plugins/two-factor` | `twoFactorClient` | +| Organizations / teams | `organization` from `better-auth/plugins/organization` | `organizationClient` | +| Magic link | `magicLink` from `better-auth/plugins/magic-link` | `magicLinkClient` | +| Admin / user management | `admin` from `better-auth/plugins/admin` | `adminClient` | +| Passkeys (WebAuthn) | `passkey` from `@better-auth/passkey` | `passkeyClient` | +| Enterprise SSO (SAML/OIDC) | `sso` from `@better-auth/sso` | — | +| Stripe subscriptions | `stripe` from `@better-auth/stripe` | `stripeClient` | +| Third-party tokens via Vercel Connect | `genericOAuth` + `connect` from `@vercel/connect/betterauth` | — | + +### Agent Tooling + +Install the official Better Auth skills for deeper, version-aware guidance (planning questionnaire, adapters, migrations, best practices): + +```bash +npx skills add better-auth/skills +``` + +Docs are versioned. Match the `better-auth` version in the lockfile, then start from [better-auth.com/llms.txt](https://better-auth.com/llms.txt) or the docs MCP server (`https://mcp.better-auth.com/mcp`, or `npx auth@latest mcp --cursor` to register it). + ## Descope Descope is available on the Vercel Marketplace with native integration support. @@ -210,7 +496,7 @@ npm install @descope/nextjs-sdk ``` -### Provider and Middleware +### Provider and Proxy ```tsx // app/layout.tsx @@ -232,7 +518,7 @@ ``` ```ts -// middleware.ts +// proxy.ts import { authMiddleware } from "@descope/nextjs-sdk/server"; export default authMiddleware({ @@ -275,20 +561,20 @@ ```env AUTH0_SECRET=<random-secret> -AUTH0_BASE_URL=http://localhost:3000 -AUTH0_ISSUER_BASE_URL=https://your-tenant.auth0.com +APP_BASE_URL=http://localhost:3000 # optional: omit on Vercel previews and the SDK infers it from the request host +AUTH0_DOMAIN=your-tenant.auth0.com AUTH0_CLIENT_ID=<client-id> AUTH0_CLIENT_SECRET=<client-secret> ``` -### Middleware +### Proxy ```ts -// middleware.ts +// proxy.ts import { auth0 } from "@/lib/auth0"; -import { NextRequest, NextResponse } from "next/server"; +import type { NextRequest } from "next/server"; -export async function middleware(request: NextRequest) { +export async function proxy(request: NextRequest) { return await auth0.middleware(request); } @@ -315,6 +601,22 @@ } ``` +## Vercel-Native Identity Primitives + +These are not replacements for Clerk, Descope, or Auth0. They cover cases where the identity comes from Vercel itself or where you need Vercel to hold the keys. + +### Sign in with Vercel + +Let users log in with their Vercel account. Vercel's Identity Provider implements OAuth 2.0 and OpenID Connect: register an App in the dashboard, redirect to `https://vercel.com/oauth/authorize` with PKCE (`code_challenge_method: 'S256'`), `state`, and `nonce`, then exchange the `code` at `https://api.vercel.com/login/oauth/token`. Access tokens last 1 hour; refresh tokens last 30 days and rotate on use. Never hand-roll the token exchange without PKCE, state, and nonce checks. Docs: https://vercel.com/docs/sign-in-with-vercel/getting-started + +### Vercel Passport (deployment protection) + +Passport protects whole deployments behind your own OIDC identity provider (Okta, Microsoft Entra ID, Auth0, or any OIDC-compatible provider). Vercel Connect stores the OAuth application configuration, and Vercel redirects unauthenticated visitors before any request reaches your code. Use it for internal tools and previews instead of application-level auth. Your app can read the verified visitor identity server-side or verify a forwarded Passport token as a JWT. Enterprise plan; GA since July 2026. Docs: https://vercel.com/docs/passport + +### Vercel KMS (managed signing keys) + +KMS signs JWTs and messages with keys that never leave Vercel. Create an issuer in the team's Key Management settings, install `@vercel/kms`, and call `signJWT({ issuerId, claims, ttl })` (resolves to `{ token, keyId, algorithm, fingerprint }`; `@vercel/kms` 0.3.0+, `signToken` is deprecated) inside a route handler or Server Component; the function's OIDC token authorizes the request automatically. Relying parties verify against the published JWKS at `https://kms.vercel.com/<issuerId>/jwks.json`. Use it instead of storing private signing keys in environment variables. Docs: https://vercel.com/docs/kms + ## Decision Matrix | Need | Recommended | Why | @@ -324,32 +626,43 @@ | Enterprise SSO / SAML / multi-tenant | Auth0 | Deep enterprise identity support | | Pre-built UI components | Clerk | Drop-in `<SignIn />`, `<UserButton />` | | Vercel unified billing | Clerk or Descope | Both are native Marketplace integrations | +| Auth in your own database, no hosted vendor | Better Auth | Runs in your app, data in your own database, no vendor dashboard to configure | +| Not Next.js (SvelteKit, Nuxt, Hono, Expo, plain Node) | Better Auth | Framework-agnostic handler + client adapters | +| Orgs, 2FA, passkeys, SSO, Stripe as code | Better Auth | Plugin system with generated schema | +| "Log in with Vercel" for a developer tool | Sign in with Vercel | Vercel is the identity provider | +| Restrict a deployment to employees behind Okta/Entra | Vercel Passport | Platform-level, no app code | +| Sign JWTs without storing private keys | Vercel KMS | Managed keys, OIDC-authorized signing | ## Clerk Core 3 Breaking Changes (March 2026) Clerk provides an upgrade CLI that scans your codebase and applies codemods: `npx @clerk/upgrade`. Requires **Node.js 20.9.0+**. -- **`auth()` is async** — always use `const { userId } = await auth()`, not synchronous -- **`auth.protect()` moved** — use `await auth.protect()` directly, not from the return value of `auth()` -- **`clerkClient()` is async** — use `await clerkClient()` in middleware handlers -- **`authMiddleware()` removed** — migrate to `clerkMiddleware()` -- **`@clerk/types` deprecated** — import types from SDK subpath exports: `import type { UserResource } from '@clerk/react/types'` (works from any SDK package) -- **`ClerkProvider` no longer forces dynamic rendering** — pass the `dynamic` prop if needed -- **Cache components** — when using Next.js cache components, place `<ClerkProvider>` inside `<body>`, not wrapping `<html>` -- **Satellite domains** — new `satelliteAutoSync` option skips handshake redirects when no session cookies exist -- **Smaller bundles** — React is now shared across framework SDKs (~50KB gzipped savings) -- **Better offline handling** — `getToken()` now correctly distinguishes signed-out from offline states +- **`SignedIn`/`SignedOut`/`Protect` replaced by `Show`** — e.g. `<Protect role="admin">` → `<Show when={{ role: 'admin' }}>` +- **Package renames** — `@clerk/clerk-react` → `@clerk/react`, `@clerk/clerk-expo` → `@clerk/expo` +- **`ClerkProvider` must be inside `<body>`, not wrapping `<html>`** — the CLI handles this automatically +- **`@clerk/types` removed** — import types from the SDK's own `/types` entry point, or `@clerk/shared/types` for framework-agnostic code +- **Redirect props renamed** — `afterSignInUrl`/`afterSignUpUrl`/`redirectUrl` → `fallbackRedirectUrl`/`signUpFallbackRedirectUrl`/`forceRedirectUrl` +- **Minimum Next.js version: 15.2.3** — Next.js 13 and 14 are no longer supported +- **Satellite domains** — apps no longer auto-redirect on first visit; set `satelliteAutoSync: true` in middleware and `ClerkProvider` to restore Core 2 behavior +- **`getToken()` throws `ClerkOfflineError` when offline** — previously returned `null`; still returns `null` when signed out ## Cross-References - **Marketplace install and env var provisioning** → `⤳ skill: marketplace` -- **Middleware routing patterns** → `⤳ skill: routing-middleware` +- **Proxy and Routing Middleware patterns** → `⤳ skill: routing-middleware` +- **Accessing protected deployments from CLI or tests** → `⤳ skill: access-protected-vercel-deployment` - **Environment variable management** → `⤳ skill: env-vars` -- **Vercel OAuth (Sign in with Vercel)** → `⤳ skill: sign-in-with-vercel` +- **Neon Postgres / Upstash Redis for Better Auth** → `⤳ skill: vercel-storage` +- **Third-party OAuth tokens through Better Auth (`@vercel/connect/betterauth`)** → `⤳ skill: vercel-connect` ## Official Documentation +- [Better Auth Docs](https://better-auth.com/docs) · [Next.js integration](https://better-auth.com/docs/integrations/next) · [Sign in with Vercel](https://better-auth.com/docs/authentication/vercel) +- [Better Auth agent skills](https://github.com/better-auth/skills) - [Clerk + Vercel Marketplace](https://clerk.com/docs/deployments/vercel) - [Clerk Next.js Quickstart](https://clerk.com/docs/quickstarts/nextjs) - [Descope Next.js SDK](https://docs.descope.com/getting-started/nextjs) - [Auth0 Next.js SDK](https://auth0.com/docs/quickstart/webapp/nextjs) +- [Sign in with Vercel](https://vercel.com/docs/sign-in-with-vercel) +- [Vercel Passport](https://vercel.com/docs/passport) +- [Vercel KMS](https://vercel.com/docs/kms)
Full snapshot data
{
"description": "Authentication integration guidance — Clerk (native Vercel Marketplace), Better Auth, Descope, and Auth0 setup for Next.js applications, plus Sign in with Vercel, Vercel Passport, and Vercel KMS. Covers server config, route handlers, proxy.ts auth patterns, sign-in/sign-up flows, and Marketplace provisioning. Use when implementing user authentication, sessions, protected routes, or protecting deployments.",
"included_files": [
{
"relative_path": "agents/openai.yaml",
"size_in_bytes": 170
}
],
"name": "auth",
"skill_md_contents": "---\nname: auth\ndescription: Authentication integration guidance — Clerk (native Vercel Marketplace), Better Auth, Descope, and Auth0 setup for Next.js applications, plus Sign in with Vercel, Vercel Passport, and Vercel KMS. Covers server config, route handlers, proxy.ts auth patterns, sign-in/sign-up flows, and Marketplace provisioning. Use when implementing user authentication, sessions, protected routes, or protecting deployments.\nmetadata:\n priority: 6\n docs:\n - \"https://authjs.dev/getting-started\"\n - \"https://nextjs.org/docs/app/guides/authentication\"\n - \"https://better-auth.com/llms.txt\"\n sitemap: \"https://authjs.dev/sitemap.xml\"\n pathPatterns:\n - 'proxy.ts'\n - 'proxy.js'\n - 'src/proxy.ts'\n - 'src/proxy.js'\n - 'middleware.ts'\n - 'middleware.js'\n - 'src/middleware.ts'\n - 'src/middleware.js'\n - 'clerk.config.*'\n - 'app/sign-in/**'\n - 'app/sign-up/**'\n - 'src/app/sign-in/**'\n - 'src/app/sign-up/**'\n - 'app/(auth)/**'\n - 'src/app/(auth)/**'\n - 'auth.config.*'\n - 'auth.ts'\n - 'auth.js'\n - 'lib/auth.ts'\n - 'src/lib/auth.ts'\n - 'lib/auth-client.ts'\n - 'src/lib/auth-client.ts'\n - 'app/api/auth/[...all]/**'\n - 'src/app/api/auth/[...all]/**'\n bashPatterns:\n - '\\bnpm\\s+(install|i|add)\\s+[^\\n]*@clerk/nextjs\\b'\n - '\\bpnpm\\s+(install|i|add)\\s+[^\\n]*@clerk/nextjs\\b'\n - '\\bbun\\s+(install|i|add)\\s+[^\\n]*@clerk/nextjs\\b'\n - '\\byarn\\s+add\\s+[^\\n]*@clerk/nextjs\\b'\n - '\\bnpm\\s+(install|i|add)\\s+[^\\n]*@descope/nextjs-sdk\\b'\n - '\\bpnpm\\s+(install|i|add)\\s+[^\\n]*@descope/nextjs-sdk\\b'\n - '\\bbun\\s+(install|i|add)\\s+[^\\n]*@descope/nextjs-sdk\\b'\n - '\\byarn\\s+add\\s+[^\\n]*@descope/nextjs-sdk\\b'\n - '\\bnpm\\s+(install|i|add)\\s+[^\\n]*@auth0/nextjs-auth0\\b'\n - '\\bpnpm\\s+(install|i|add)\\s+[^\\n]*@auth0/nextjs-auth0\\b'\n - '\\bbun\\s+(install|i|add)\\s+[^\\n]*@auth0/nextjs-auth0\\b'\n - '\\byarn\\s+add\\s+[^\\n]*@auth0/nextjs-auth0\\b'\n - '\\bnpm\\s+(install|i|add)\\s+[^\\n]*@vercel/kms\\b'\n - '\\bpnpm\\s+(install|i|add)\\s+[^\\n]*@vercel/kms\\b'\n - '\\bbun\\s+(install|i|add)\\s+[^\\n]*@vercel/kms\\b'\n - '\\byarn\\s+add\\s+[^\\n]*@vercel/kms\\b'\n - '\\bnpm\\s+(install|i|add)\\s+[^\\n]*\\bbetter-auth\\b'\n - '\\bpnpm\\s+(install|i|add)\\s+[^\\n]*\\bbetter-auth\\b'\n - '\\bbun\\s+(install|i|add)\\s+[^\\n]*\\bbetter-auth\\b'\n - '\\byarn\\s+add\\s+[^\\n]*\\bbetter-auth\\b'\n - '\\b(npx|bunx|pnpm\\s+dlx)\\s+(auth@latest|@better-auth/cli)\\b'\n importPatterns:\n - \"@vercel/kms\"\n - \"better-auth\"\nvalidate:\n -\n pattern: 'VERCEL_CLIENT_(ID|SECRET)|vercel\\.com/oauth/(authorize|access_token|token)'\n message: 'Hand-rolled Vercel OAuth detected. Use the Sign in with Vercel OIDC provider (or the built-in `vercel` social provider in Better Auth) instead of manual token exchange.'\n severity: recommended\n skipIfFileContains: 'signInWithVercel|@vercel/auth|better-auth|socialProviders'\nretrieval:\n aliases:\n - authentication\n - login system\n - sign in\n - auth flow\n - sign in with vercel\n - passport\n - kms\n intents:\n - add auth\n - protect routes\n - manage sessions\n - implement login\n - secure api endpoints\n entities:\n - NextAuth\n - Auth.js\n - Better Auth\n - betterAuth\n - authClient\n - JWT\n - OAuth\n - session\n - middleware\n - getServerSession\n - Vercel Passport\n - Okta\n - Microsoft Entra ID\n - Vercel KMS\n - signToken\n examples:\n - add login to my app\n - protect this route with auth\n - set up NextAuth\n - set up Better Auth\n - add better auth to my next app\nchainTo:\n -\n pattern: 'export\\s+(default\\s+)?function\\s+middleware'\n targetSkill: routing-middleware\n message: 'Auth logic in a middleware() export — Next.js 16 uses proxy.ts with a proxy() export. Loading Routing Middleware guidance for the migration.'\n -\n pattern: 'from\\s+[''\\\"](jsonwebtoken)[''\"]|require\\s*\\(\\s*[''\\\"](jsonwebtoken)[''\"]|jwt\\.sign\\s*\\('\n targetSkill: auth\n message: 'Manual JWT handling with jsonwebtoken detected — use Clerk, Better Auth, or Auth.js for built-in session handling, CSRF protection, and token rotation.'\n skipIfFileContains: 'better-auth|@clerk|next-auth'\n -\n pattern: 'from\\s+[''\\\"](next-auth)[''\"]|NextAuthOptions|authOptions\\s*:'\n targetSkill: auth\n message: 'Legacy next-auth (v4) pattern detected — loading auth guidance for Auth.js v5 migration with the new universal auth() helper.'\n -\n pattern: 'from\\s+[''\"]@clerk/nextjs[''\"]'\n targetSkill: auth\n message: 'Clerk import detected — loading Auth guidance for Clerk v7 patterns, middleware setup, organization handling, and Vercel Marketplace integration.'\n skipIfFileContains: 'clerkMiddleware|ClerkProvider'\n -\n pattern: \"bcrypt|argon2\"\n targetSkill: auth\n message: 'Manual password hashing detected (bcrypt/argon2) — use Clerk, Better Auth, or Auth0 for authentication with built-in password hashing and rate limiting.'\n skipIfFileContains: \"@clerk|@auth0|better-auth\"\n -\n pattern: 'from\\s+[''\"]better-auth[''\"]|betterAuth\\s*\\('\n targetSkill: auth\n message: 'Better Auth config detected — loading Auth guidance for the Next.js route handler, nextCookies plugin, cookie-only middleware checks, cookie cache, and Marketplace Postgres/Redis wiring.'\n skipIfFileContains: 'nextCookies|toNextJsHandler'\n---\n\n# Authentication Integrations\n\nYou are an expert in authentication for Vercel-deployed applications — covering Clerk (native Vercel Marketplace integration), Better Auth (self-hosted, with data in your own database), Descope, and Auth0 for application sign-in, plus Vercel's own primitives: Sign in with Vercel (OAuth/OIDC provider), Passport (deployment protection with your identity provider), and KMS (managed signing keys).\n\nAll Next.js examples target Next.js 16, where the request-interception file is `proxy.ts` (exporting `proxy`). On Next.js 15 or earlier the same code lives in `middleware.ts` (exporting `middleware`).\n\n## Clerk (Recommended — Native Marketplace Integration)\n\nClerk is a native Vercel Marketplace integration with auto-provisioned environment variables and unified billing. Current SDK: `@clerk/nextjs` v7 (Core 3, March 2026).\n\n### Install via Marketplace\n\n```bash\n# Install Clerk from Vercel Marketplace (auto-provisions env vars)\nvercel integration add clerk\n```\n\nAuto-provisioned environment variables:\n- `CLERK_SECRET_KEY` — server-side API key\n- `NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY` — client-side publishable key\n\n### SDK Setup\n\n```bash\n# Install the Clerk Next.js SDK\nnpm install @clerk/nextjs\n```\n\n### Proxy Configuration\n\n```ts\n// proxy.ts (Next.js 16; middleware.ts on Next.js 15 and earlier)\nimport { clerkMiddleware } from \"@clerk/nextjs/server\";\n\nexport default clerkMiddleware();\n\nexport const config = {\n matcher: [\n // Skip Next.js internals and static files\n \"/((?!_next|[^?]*\\\\.(?:html?|css|js(?!on)|jpe?g|webp|png|gif|svg|ttf|woff2?|ico|csv|docx?|xlsx?|zip|webmanifest)).*)\",\n // Always run for API routes\n \"/(api|trpc)(.*)\",\n ],\n};\n```\n\n### Protect Routes\n\n```ts\n// proxy.ts — protect specific routes\nimport { clerkMiddleware, createRouteMatcher } from \"@clerk/nextjs/server\";\n\nconst isProtectedRoute = createRouteMatcher([\"/dashboard(.*)\", \"/api(.*)\"]);\n\nexport default clerkMiddleware(async (auth, req) => {\n if (isProtectedRoute(req)) {\n await auth.protect();\n }\n});\n```\n\n### Frontend API Proxy (Core 3)\n\nProxy Clerk's Frontend API through your own domain to avoid third-party requests:\n\n```ts\n// proxy.ts\nexport default clerkMiddleware({\n frontendApiProxy: { enabled: true },\n});\n```\n\n### Provider Setup\n\n```tsx\n// app/layout.tsx\nimport { ClerkProvider } from \"@clerk/nextjs\";\n\nexport default function RootLayout({\n children,\n}: {\n children: React.ReactNode;\n}) {\n return (\n <html lang=\"en\">\n <body>\n <ClerkProvider>{children}</ClerkProvider>\n </body>\n </html>\n );\n}\n```\n\n### Sign-In and Sign-Up Pages\n\n```tsx\n// app/sign-in/[[...sign-in]]/page.tsx\nimport { SignIn } from \"@clerk/nextjs\";\n\nexport default function Page() {\n return <SignIn />;\n}\n```\n\n```tsx\n// app/sign-up/[[...sign-up]]/page.tsx\nimport { SignUp } from \"@clerk/nextjs\";\n\nexport default function Page() {\n return <SignUp />;\n}\n```\n\nAdd routing env vars to `.env.local`:\n\n```env\nNEXT_PUBLIC_CLERK_SIGN_IN_URL=/sign-in\nNEXT_PUBLIC_CLERK_SIGN_UP_URL=/sign-up\n```\n\n### Access User Data\n\n```tsx\n// Server component\nimport { currentUser } from \"@clerk/nextjs/server\";\n\nexport default async function Page() {\n const user = await currentUser();\n return <p>Hello, {user?.firstName}</p>;\n}\n```\n\n```tsx\n// Client component\n\"use client\";\nimport { useUser } from \"@clerk/nextjs\";\n\nexport default function UserGreeting() {\n const { user, isLoaded } = useUser();\n if (!isLoaded) return null;\n return <p>Hello, {user?.firstName}</p>;\n}\n```\n\n### API Route Protection\n\n```ts\n// app/api/protected/route.ts\nimport { auth } from \"@clerk/nextjs/server\";\n\nexport async function GET() {\n const { userId } = await auth();\n if (!userId) {\n return Response.json({ error: \"Unauthorized\" }, { status: 401 });\n }\n return Response.json({ userId });\n}\n```\n\n## Better Auth (Self-Hosted)\n\nBetter Auth is a framework-agnostic TypeScript auth library that runs inside your app. Users, sessions, and accounts live in your own database, so the only external dependency is the database itself. Choose it when the user wants auth inside their app with data in their own database, or is building on a framework other than Next.js. Current release line: v1.7.\n\n### Agent Workflow\n\n1. **Detect** framework (Next.js App/Pages Router, SvelteKit, Nuxt, Hono…), database/ORM (`prisma/schema.prisma`, `drizzle.config.ts`, `pg`, `@neondatabase/serverless`), and package manager from the lockfile.\n2. **Install** `better-auth` plus the DB driver. Provision Postgres from the Marketplace if the project has no database.\n3. **Create** `lib/auth.ts` (server) and `lib/auth-client.ts` (client).\n4. **Mount** the route handler at `app/api/auth/[...all]/route.ts`.\n5. **Migrate** with `npx auth@latest migrate` (built-in adapter) or `generate` + the ORM's migrate (Prisma/Drizzle).\n6. **Protect** routes: cookie check in `proxy.ts`, real `getSession()` in pages/route handlers.\n7. **Verify** `GET /api/auth/ok` returns `{ \"status\": \"ok\" }`, then run a sign-up → sign-in → `getSession()` pass.\n8. **Re-run migrate** after every plugin change.\n\n### Install\n\n```bash\nnpm install better-auth pg\n# Postgres from the Marketplace (auto-provisions DATABASE_URL)\nvercel integration add neon\n```\n\n### Environment Variables\n\n```env\nBETTER_AUTH_SECRET=<openssl rand -base64 32>\nBETTER_AUTH_URL=http://localhost:3000\n```\n\n- **Production:** set `BETTER_AUTH_URL` to your production domain.\n- **Preview:** leave `BETTER_AUTH_URL` unset for the Preview environment. Better Auth infers the base URL from the incoming request, so every preview URL works without config. `VERCEL_URL` is **not** read automatically.\n- OAuth providers need registered redirect URIs (`<base>/api/auth/callback/<provider>`), so social login on previews needs a stable branch alias.\n\n### Server Config\n\n```ts\n// lib/auth.ts\nimport { betterAuth } from \"better-auth\";\nimport { nextCookies } from \"better-auth/next-js\";\nimport { Pool } from \"pg\";\n\nexport const auth = betterAuth({\n database: new Pool({ connectionString: process.env.DATABASE_URL }),\n emailAndPassword: { enabled: true },\n socialProviders: {\n github: {\n clientId: process.env.GITHUB_CLIENT_ID!,\n clientSecret: process.env.GITHUB_CLIENT_SECRET!,\n },\n // Sign in with Vercel — create a Vercel App in the dashboard for credentials\n vercel: {\n clientId: process.env.VERCEL_CLIENT_ID!,\n clientSecret: process.env.VERCEL_CLIENT_SECRET!,\n },\n },\n session: {\n // Signed cookie cache: most getSession() calls skip the database\n cookieCache: { enabled: true, maxAge: 5 * 60 },\n },\n plugins: [nextCookies()], // keep last — sets cookies from Server Actions\n});\n```\n\nPrisma / Drizzle / MongoDB users pass an adapter instead of a pool: `prismaAdapter(prisma, { provider: \"postgresql\" })` from `better-auth/adapters/prisma`, `drizzleAdapter(db, { provider: \"pg\" })` from `better-auth/adapters/drizzle`.\n\n### Route Handler\n\n```ts\n// app/api/auth/[...all]/route.ts\nimport { auth } from \"@/lib/auth\";\nimport { toNextJsHandler } from \"better-auth/next-js\";\n\nexport const { GET, POST } = toNextJsHandler(auth);\n```\n\n### Database Schema\n\n```bash\nnpx auth@latest migrate # built-in adapter (pg / mysql / sqlite): applies directly\nnpx auth@latest generate # Prisma / Drizzle: writes the schema, then run your ORM's migrate\n```\n\nRe-run after adding or removing plugins. Verify with `GET /api/auth/ok` → `{ \"status\": \"ok\" }`.\n\n### Client\n\n```ts\n// lib/auth-client.ts\nimport { createAuthClient } from \"better-auth/react\";\n\nexport const authClient = createAuthClient();\n```\n\n```tsx\n\"use client\";\nimport { authClient } from \"@/lib/auth-client\";\n\n// Sign in\nawait authClient.signIn.email({ email, password, callbackURL: \"/dashboard\" });\nawait authClient.signIn.social({ provider: \"github\", callbackURL: \"/dashboard\" });\nawait authClient.signUp.email({ email, password, name });\nawait authClient.signOut();\n\n// Reactive session\nconst { data: session, isPending } = authClient.useSession();\n```\n\n### Access Session Data (Server)\n\n```tsx\n// Server Component, Server Action, or Route Handler\nimport { auth } from \"@/lib/auth\";\nimport { headers } from \"next/headers\";\nimport { redirect } from \"next/navigation\";\n\nexport default async function Page() {\n const session = await auth.api.getSession({ headers: await headers() });\n if (!session) redirect(\"/sign-in\");\n return <p>Hello, {session.user.name}</p>;\n}\n```\n\nEvery endpoint (including plugin endpoints) is callable server-side via `auth.api.*` — no HTTP round-trip.\n\n### Protect Routes\n\nOnly check for the session **cookie** in middleware/proxy — never call the database there. Do the real check in the page or route handler.\n\n```ts\n// proxy.ts (Next.js 16) — rename to middleware.ts on Next.js 15\nimport { NextRequest, NextResponse } from \"next/server\";\nimport { getSessionCookie } from \"better-auth/cookies\";\n\nexport function proxy(request: NextRequest) {\n if (!getSessionCookie(request)) {\n return NextResponse.redirect(new URL(\"/sign-in\", request.url));\n }\n return NextResponse.next();\n}\n\nexport const config = { matcher: [\"/dashboard/:path*\"] };\n```\n\n### Keep It Fast on Vercel\n\n- **Cookie cache on** (`session.cookieCache`) — avoids a DB read per request in Fluid Compute functions.\n- **Redis for shared state** — `vercel integration add upstash`, then pass a `secondaryStorage` adapter. Sessions and rate-limit counters move to Redis; the default in-memory rate limiter does not share state across function instances. Set `rateLimit.storage: \"secondary-storage\"`.\n- **Import plugins from subpaths** for tree-shaking: `import { twoFactor } from \"better-auth/plugins/two-factor\"`, not `\"better-auth/plugins\"`.\n- **Cookie check only in middleware** — `getSessionCookie()` is synchronous and works on the Edge runtime; `auth.api.getSession()` in middleware requires the Node.js runtime and costs a DB hit per request.\n- **Separate frontend origin?** Add it to `trustedOrigins` (wildcards allowed: `\"https://*.vercel.app\"`). Same-origin apps need nothing.\n\n### Common Mistakes\n\n| Symptom | Cause | Fix |\n|---------|-------|-----|\n| Cookies not set from a Server Action | `nextCookies()` missing or not last in `plugins` | Add it as the last plugin |\n| Middleware slow or fails on Edge | `auth.api.getSession()` in middleware | Use `getSessionCookie()`; verify in the page |\n| \"Invalid origin\" on a separate frontend | Origin not trusted | Add it to `trustedOrigins` |\n| Type errors or missing tables after adding a plugin | Schema not regenerated | Re-run `npx auth@latest migrate` / `generate` |\n| Adapter can't find a model | Config uses the DB table name | Use the ORM **model** name (`modelName: \"user\"`, not `\"users\"`) |\n| Rate limits reset per request in production | Default in-memory rate-limit storage | Use `secondaryStorage` (Redis) or `rateLimit.storage: \"database\"` |\n| Callback URL wrong on Vercel | `BETTER_AUTH_URL` points at localhost or a preview | Set the production domain in Production; leave unset for Preview |\n\n### Plugins\n\nServer plugin + matching client plugin + re-run migrations.\n\n| Feature | Server import | Client plugin |\n|---------|--------------|---------------|\n| Two-factor (TOTP/OTP) | `twoFactor` from `better-auth/plugins/two-factor` | `twoFactorClient` |\n| Organizations / teams | `organization` from `better-auth/plugins/organization` | `organizationClient` |\n| Magic link | `magicLink` from `better-auth/plugins/magic-link` | `magicLinkClient` |\n| Admin / user management | `admin` from `better-auth/plugins/admin` | `adminClient` |\n| Passkeys (WebAuthn) | `passkey` from `@better-auth/passkey` | `passkeyClient` |\n| Enterprise SSO (SAML/OIDC) | `sso` from `@better-auth/sso` | — |\n| Stripe subscriptions | `stripe` from `@better-auth/stripe` | `stripeClient` |\n| Third-party tokens via Vercel Connect | `genericOAuth` + `connect` from `@vercel/connect/betterauth` | — |\n\n### Agent Tooling\n\nInstall the official Better Auth skills for deeper, version-aware guidance (planning questionnaire, adapters, migrations, best practices):\n\n```bash\nnpx skills add better-auth/skills\n```\n\nDocs are versioned. Match the `better-auth` version in the lockfile, then start from [better-auth.com/llms.txt](https://better-auth.com/llms.txt) or the docs MCP server (`https://mcp.better-auth.com/mcp`, or `npx auth@latest mcp --cursor` to register it).\n\n## Descope\n\nDescope is available on the Vercel Marketplace with native integration support.\n\n### Install via Marketplace\n\n```bash\nvercel integration add descope\n```\n\n### SDK Setup\n\n```bash\nnpm install @descope/nextjs-sdk\n```\n\n### Provider and Proxy\n\n```tsx\n// app/layout.tsx\nimport { AuthProvider } from \"@descope/nextjs-sdk\";\n\nexport default function RootLayout({\n children,\n}: {\n children: React.ReactNode;\n}) {\n return (\n <AuthProvider projectId={process.env.NEXT_PUBLIC_DESCOPE_PROJECT_ID!}>\n <html lang=\"en\">\n <body>{children}</body>\n </html>\n </AuthProvider>\n );\n}\n```\n\n```ts\n// proxy.ts\nimport { authMiddleware } from \"@descope/nextjs-sdk/server\";\n\nexport default authMiddleware({\n projectId: process.env.DESCOPE_PROJECT_ID!,\n publicRoutes: [\"/\", \"/sign-in\"],\n});\n```\n\n### Sign-In Flow\n\n```tsx\n\"use client\";\nimport { Descope } from \"@descope/nextjs-sdk\";\n\nexport default function SignInPage() {\n return <Descope flowId=\"sign-up-or-in\" />;\n}\n```\n\n## Auth0\n\nAuth0 provides a mature authentication platform with extensive identity provider support.\n\n### SDK Setup\n\n```bash\nnpm install @auth0/nextjs-auth0\n```\n\n### Configuration\n\n```ts\n// lib/auth0.ts\nimport { Auth0Client } from \"@auth0/nextjs-auth0/server\";\n\nexport const auth0 = new Auth0Client();\n```\n\nRequired environment variables:\n\n```env\nAUTH0_SECRET=<random-secret>\nAPP_BASE_URL=http://localhost:3000 # optional: omit on Vercel previews and the SDK infers it from the request host\nAUTH0_DOMAIN=your-tenant.auth0.com\nAUTH0_CLIENT_ID=<client-id>\nAUTH0_CLIENT_SECRET=<client-secret>\n```\n\n### Proxy\n\n```ts\n// proxy.ts\nimport { auth0 } from \"@/lib/auth0\";\nimport type { NextRequest } from \"next/server\";\n\nexport async function proxy(request: NextRequest) {\n return await auth0.middleware(request);\n}\n\nexport const config = {\n matcher: [\n \"/((?!_next/static|_next/image|favicon.ico|sitemap.xml|robots.txt).*)\",\n ],\n};\n```\n\n### Access Session Data\n\n```tsx\n// Server component\nimport { auth0 } from \"@/lib/auth0\";\n\nexport default async function Page() {\n const session = await auth0.getSession();\n return session ? (\n <p>Hello, {session.user.name}</p>\n ) : (\n <a href=\"/auth/login\">Log in</a>\n );\n}\n```\n\n## Vercel-Native Identity Primitives\n\nThese are not replacements for Clerk, Descope, or Auth0. They cover cases where the identity comes from Vercel itself or where you need Vercel to hold the keys.\n\n### Sign in with Vercel\n\nLet users log in with their Vercel account. Vercel's Identity Provider implements OAuth 2.0 and OpenID Connect: register an App in the dashboard, redirect to `https://vercel.com/oauth/authorize` with PKCE (`code_challenge_method: 'S256'`), `state`, and `nonce`, then exchange the `code` at `https://api.vercel.com/login/oauth/token`. Access tokens last 1 hour; refresh tokens last 30 days and rotate on use. Never hand-roll the token exchange without PKCE, state, and nonce checks. Docs: https://vercel.com/docs/sign-in-with-vercel/getting-started\n\n### Vercel Passport (deployment protection)\n\nPassport protects whole deployments behind your own OIDC identity provider (Okta, Microsoft Entra ID, Auth0, or any OIDC-compatible provider). Vercel Connect stores the OAuth application configuration, and Vercel redirects unauthenticated visitors before any request reaches your code. Use it for internal tools and previews instead of application-level auth. Your app can read the verified visitor identity server-side or verify a forwarded Passport token as a JWT. Enterprise plan; GA since July 2026. Docs: https://vercel.com/docs/passport\n\n### Vercel KMS (managed signing keys)\n\nKMS signs JWTs and messages with keys that never leave Vercel. Create an issuer in the team's Key Management settings, install `@vercel/kms`, and call `signJWT({ issuerId, claims, ttl })` (resolves to `{ token, keyId, algorithm, fingerprint }`; `@vercel/kms` 0.3.0+, `signToken` is deprecated) inside a route handler or Server Component; the function's OIDC token authorizes the request automatically. Relying parties verify against the published JWKS at `https://kms.vercel.com/<issuerId>/jwks.json`. Use it instead of storing private signing keys in environment variables. Docs: https://vercel.com/docs/kms\n\n## Decision Matrix\n\n| Need | Recommended | Why |\n|------|------------|-----|\n| Fastest setup on Vercel | Clerk | Native Marketplace, auto-provisioned env vars |\n| Passwordless / social login flows | Descope | Visual flow builder, Marketplace native |\n| Enterprise SSO / SAML / multi-tenant | Auth0 | Deep enterprise identity support |\n| Pre-built UI components | Clerk | Drop-in `<SignIn />`, `<UserButton />` |\n| Vercel unified billing | Clerk or Descope | Both are native Marketplace integrations |\n| Auth in your own database, no hosted vendor | Better Auth | Runs in your app, data in your own database, no vendor dashboard to configure |\n| Not Next.js (SvelteKit, Nuxt, Hono, Expo, plain Node) | Better Auth | Framework-agnostic handler + client adapters |\n| Orgs, 2FA, passkeys, SSO, Stripe as code | Better Auth | Plugin system with generated schema |\n| \"Log in with Vercel\" for a developer tool | Sign in with Vercel | Vercel is the identity provider |\n| Restrict a deployment to employees behind Okta/Entra | Vercel Passport | Platform-level, no app code |\n| Sign JWTs without storing private keys | Vercel KMS | Managed keys, OIDC-authorized signing |\n\n## Clerk Core 3 Breaking Changes (March 2026)\n\nClerk provides an upgrade CLI that scans your codebase and applies codemods: `npx @clerk/upgrade`. Requires **Node.js 20.9.0+**.\n\n- **`SignedIn`/`SignedOut`/`Protect` replaced by `Show`** — e.g. `<Protect role=\"admin\">` → `<Show when={{ role: 'admin' }}>`\n- **Package renames** — `@clerk/clerk-react` → `@clerk/react`, `@clerk/clerk-expo` → `@clerk/expo`\n- **`ClerkProvider` must be inside `<body>`, not wrapping `<html>`** — the CLI handles this automatically\n- **`@clerk/types` removed** — import types from the SDK's own `/types` entry point, or `@clerk/shared/types` for framework-agnostic code\n- **Redirect props renamed** — `afterSignInUrl`/`afterSignUpUrl`/`redirectUrl` → `fallbackRedirectUrl`/`signUpFallbackRedirectUrl`/`forceRedirectUrl`\n- **Minimum Next.js version: 15.2.3** — Next.js 13 and 14 are no longer supported\n- **Satellite domains** — apps no longer auto-redirect on first visit; set `satelliteAutoSync: true` in middleware and `ClerkProvider` to restore Core 2 behavior\n- **`getToken()` throws `ClerkOfflineError` when offline** — previously returned `null`; still returns `null` when signed out\n\n## Cross-References\n\n- **Marketplace install and env var provisioning** → `⤳ skill: marketplace`\n- **Proxy and Routing Middleware patterns** → `⤳ skill: routing-middleware`\n- **Accessing protected deployments from CLI or tests** → `⤳ skill: access-protected-vercel-deployment`\n- **Environment variable management** → `⤳ skill: env-vars`\n- **Neon Postgres / Upstash Redis for Better Auth** → `⤳ skill: vercel-storage`\n- **Third-party OAuth tokens through Better Auth (`@vercel/connect/betterauth`)** → `⤳ skill: vercel-connect`\n\n## Official Documentation\n\n- [Better Auth Docs](https://better-auth.com/docs) · [Next.js integration](https://better-auth.com/docs/integrations/next) · [Sign in with Vercel](https://better-auth.com/docs/authentication/vercel)\n- [Better Auth agent skills](https://github.com/better-auth/skills)\n- [Clerk + Vercel Marketplace](https://clerk.com/docs/deployments/vercel)\n- [Clerk Next.js Quickstart](https://clerk.com/docs/quickstarts/nextjs)\n- [Descope Next.js SDK](https://docs.descope.com/getting-started/nextjs)\n- [Auth0 Next.js SDK](https://auth0.com/docs/quickstart/webapp/nextjs)\n- [Sign in with Vercel](https://vercel.com/docs/sign-in-with-vercel)\n- [Vercel Passport](https://vercel.com/docs/passport)\n- [Vercel KMS](https://vercel.com/docs/kms)\n"
}SHA-256 of public snapshot: 75e3b0ce1edec9dd8101d55126edb56b0b3f4fcd7b5aa0618d71d79d078c4eb9