Receber por email
← Voltar para o catálogo

clerk-auth

Expert patterns for Clerk auth implementation, middleware,

41.2kestrelas
Atualizado há 4 meses

Ver no GitHub ↗ Licença: MIT

Como adicionar

/plugin marketplace add sickn33/antigravity-awesome-skills

O comando exato pode variar conforme o repositório. Confira o README no GitHub.

Para o autor da skill

Cole no README do seu repo

Mostra que sua skill está catalogada na Skillteca, gera backlink e tráfego rastreável.

[![Skillteca](https://www.skillteca.com.br/api/badge/clerk-auth-mpte24bb/svg)](https://www.skillteca.com.br/skills/clerk-auth-mpte24bb)

Skills relacionadas

Ver todas de Desenvolvimento →

Alerta por categoria

Receba novas skills de Desenvolvimento toda segunda

1 email curto, só com as skills novas de Desenvolvimento. 4 minutos de leitura, sem spam, cancela com 1 clique.

Você confirma o email no primeiro envio. Sem spam. Cancela com 1 clique.

Ler descrição completa

Clerk Authentication

Expert patterns for Clerk auth implementation, middleware, organizations, webhooks, and user sync

Patterns

Next.js App Router Setup

Complete Clerk setup for Next.js 14/15 App Router.

Includes ClerkProvider, environment variables, and basic sign-in/sign-up components.

Key components:

  • ClerkProvider: Wraps app for auth context
  • <SignIn />, <SignUp />: Pre-built auth forms
  • <UserButton />: User menu with session management

Code_example

Environment variables (.env.local)

NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_test_... CLERK_SECRET_KEY=sk_test_... 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=/onboarding

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

export default function RootLayout({ children, }: { children: React.ReactNode; }) { return ( <ClerkProvider> <html lang="en"> <body>{children}</body> </html> </ClerkProvider> ); }

// app/sign-in/[[...sign-in]]/page.tsx import { SignIn } from '@clerk/nextjs';

export default function SignInPage() { return ( <div className="flex justify-center items-center min-h-screen"> <SignIn /> </div> ); }

// app/sign-up/[[...sign-up]]/page.tsx import { SignUp } from '@clerk/nextjs';

export default function SignUpPage() { return ( <div className="flex justify-center items-center min-h-screen"> <SignUp /> </div> ); }

// components/Header.tsx import { SignedIn, SignedOut, SignInButton, UserButton } from '@clerk/nextjs';

export function Header() { return ( <header className="flex justify-between p-4"> <h1>My App</h1> <SignedOut> <SignInButton /> </SignedOut> <SignedIn> <UserButton afterSignOutUrl="/" /> </SignedIn> </header> ); }

Anti_patterns

  • Pattern: ClerkProvider inside page component | Why: Provider must wrap entire app in root layout | Fix: Move ClerkProvider to app/layout.tsx
  • Pattern: Using auth() without middleware | Why: auth() requires clerkMiddleware to be configured | Fix: Set up middleware.ts with clerkMiddleware

References

  • https://clerk.com/docs/nextjs/getting-started/quickstart

Middleware Route Protection

Protect routes using clerkMiddleware and createRouteMatcher.

Best practices:

  • Single middleware.ts file at project root
  • Use createRouteMatcher for route groups
  • auth.protect() for explicit protection
  • Centralize all auth logic in middleware

Code_example

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

// Define protected route patterns const isProtectedRoute = createRouteMatcher([ '/dashboard(.)', '/settings(.)', '/api/private(.*)', ]);

// Define public routes (optional, for clarity) const isPublicRoute = createRouteMatcher([ '/', '/sign-in(.)', '/sign-up(.)', '/api/webhooks(.*)', ]);

export default clerkMiddleware(async (auth, req) => { // Protect matched routes if (isProtectedRoute(req)) { await auth.protect(); } });

export const config = { matcher: [ // Match all routes except static files '/((?!_next|[^?]\\.(?:html?|css|js(?!on)|jpe?g|webp|png|gif|svg|ttf|woff2?|ico|csv|docx?|xlsx?|zip|webmanifest)).)', // Always run for API routes '/(api|trpc)(.*)', ], };

// Advanced: Role-based protection export default clerkMiddleware(async (auth, req) => { if (isProtectedRoute(req)) { await auth.protect(); }

// Admin routes require admin role if (req.nextUrl.pathname.startsWith('/admin')) { await auth.protect({ role: 'org:admin', }); }

// Premium routes require premium permission if (req.nextUrl.pathname.startsWith('/premium')) { await auth.protect({ permission: 'org:premium:access', }); } });

Anti_patterns

  • Pattern: Multiple middleware.ts files | Why: Causes conflicts and redirect loops | Fix: Use single middleware.ts with route matchers
  • Pattern: Manual redirects in components | Why: Double redirects, missed routes | Fix: Handle all redirects in middleware
  • Pattern: Missing matcher config | Why: Middleware won't run on all routes | Fix: Add comprehensive matcher pattern

References

  • https://clerk.com/docs/reference/nextjs/clerk-middleware

Server Component Authentication

Access auth state in Server Components using auth() and currentUser().

Key functions:

  • auth(): Returns userId, sessionId, orgId, claims
  • currentUser(): Returns full User object
  • Both require clerkMiddleware to be configured

Code_example

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

export default async function DashboardPage() { const { userId } = await auth();

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

// Full user data (counts toward rate limits) const user = await currentUser();

return ( <div> <h1>Welcome, {user?.firstName}!</h1> <p>Email: {user?.emailAddresses[0]?.emailAddress}</p> </div> ); }

// Using auth() for quick checks export default async function ProtectedLayout({ children, }: { children: React.ReactNode; }) { const { userId, orgId, orgRole } = await auth();

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

// Check organization access if (!orgId) { redirect('/select-org'); }

return ( <div> <p>Organization Role: {orgRole}</p> {children} </div> ); }

// Server Action with auth check // app/actions/posts.ts 'use server'; import { auth } from '@clerk/nextjs/server';

export async function createPost(formData: FormData) { const { userId } = await auth();

if (!userId) { throw new Error('Unauthorized'); }

const title = formData.get('title') as string;

// Create post with userId const post = await prisma.post.create({ data: { title, authorId: userId, }, });

return post; }

Anti_patterns

  • Pattern: Not awaiting auth() | Why: auth() is async in App Router | Fix: Use await auth() or const { userId } = await auth()
  • Pattern: Using currentUser() for simple checks | Why: Counts toward rate limits, slower than auth() | Fix: Use auth() for userId checks, currentUser() for user data

References

  • https://clerk.com/docs/references/nextjs/auth

Client Component Hooks

Access auth state in Client Components using hooks.

Key hooks:

  • useUser(): User object and loading state
  • useAuth(): Auth state, signOut, etc.
  • useSession(): Session object
  • useOrganization(): Current organization

Code_example

// components/UserProfile.tsx 'use client'; import { useUser, useAuth } from '@clerk/nextjs';

export function UserProfile() { const { user, isLoaded, isSignedIn } = useUser(); const { signOut } = useAuth();

if (!isLoaded) { return <div>Loading...</div>; }

if (!isSignedIn) { return <div>Not signed in</div>; }

return ( <div> <img src={user.imageUrl} alt={user.fullName ?? ''} /> <h2>{user.fullName}</h2> <p>{user.emailAddresses[0]?.emailAddress}</p> <button onClick={() => signOut()}>Sign Out</button> </div> ); }

// Organization context 'use client'; import { useOrganization, useOrganizationList } from '@clerk/nextjs';

export function OrgSwitcher() { const { organization, membership } = useOrganization(); const { setActive, userMemberships } = useOrganizationList({ userMemberships: { infinite: true }, });

if (!organization) { return <p>No organization selected</p>; }

return ( <div> <p>Current: {organization.name}</p> <p>Role: {membership?.role}</p>

<select onChange={(e) => setActive?.({ organization: e.target.value })} value={organization.id} > {userMemberships.data?.map((mem) => ( <option key={mem.organization.id} value={mem.organization.id}> {mem.orga

Compartilhar X LinkedIn