# Clerk Authentication Integration Standard

> **Scope:** universal
> **Layer:** 2 (on keyword)
> **Keywords:** clerk, auth, authentication, nextjs, user management
> **Load When:** clerk authentication keywords detected

Modern authentication and user management for Next.js applications.

---

## Overview

Clerk provides:
- Pre-built UI components (SignIn, SignUp, UserProfile)
- Social auth (Google, GitHub, etc.)
- Multi-factor authentication
- Session management
- User metadata and organizations

**Primary Use Case:** Next.js 15 + App Router

---

## Core Principles

1. **Server-First**: Use server-side auth checks with `auth()` helper
2. **Route Protection**: Middleware-based protection for private routes
3. **Type Safety**: Use Clerk's TypeScript types
4. **Edge Compatible**: Works with Edge Runtime

---

## Installation & Setup

### Install Packages

```bash
npm install @clerk/nextjs
```

### Environment Variables

```bash
# .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
```

### Root Layout Wrapper

```typescript
// 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>
  );
}
```

### Middleware Protection

```typescript
// middleware.ts
import { authMiddleware } from '@clerk/nextjs';

export default authMiddleware({
  publicRoutes: ['/', '/api/webhooks/clerk'],
  ignoredRoutes: ['/api/public']
});

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

---

## Common Patterns

### Sign In Page

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

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

### Server-Side Auth Check

```typescript
// app/dashboard/page.tsx
import { auth } from '@clerk/nextjs';
import { redirect } from 'next/navigation';

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

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

  return <div>Dashboard for user {userId}</div>;
}
```

### Client Component with User Data

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

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

  if (!isLoaded) return <div>Loading...</div>;
  if (!isSignedIn) return <div>Not signed in</div>;

  return (
    <div>
      <p>Welcome, {user.firstName}!</p>
      <p>Email: {user.primaryEmailAddress?.emailAddress}</p>
    </div>
  );
}
```

### API Route Protection

```typescript
// app/api/protected/route.ts
import { auth } from '@clerk/nextjs';

export async function GET() {
  const { userId } = auth();

  if (!userId) {
    return new Response('Unauthorized', { status: 401 });
  }

  // Fetch user-specific data
  const data = await fetchUserData(userId);

  return Response.json(data);
}
```

---

## Webhook Integration

### Setup Webhook Endpoint

```typescript
// app/api/webhooks/clerk/route.ts
import { Webhook } from 'svix';
import { headers } from 'next/headers';

export async function POST(req: Request) {
  const WEBHOOK_SECRET = process.env.CLERK_WEBHOOK_SECRET!;

  const headerPayload = headers();
  const svix_id = headerPayload.get('svix-id');
  const svix_timestamp = headerPayload.get('svix-timestamp');
  const svix_signature = headerPayload.get('svix-signature');

  if (!svix_id || !svix_timestamp || !svix_signature) {
    return new Response('Missing svix headers', { status: 400 });
  }

  const payload = await req.json();
  const body = JSON.stringify(payload);

  const wh = new Webhook(WEBHOOK_SECRET);

  let evt;
  try {
    evt = wh.verify(body, {
      'svix-id': svix_id,
      'svix-timestamp': svix_timestamp,
      'svix-signature': svix_signature,
    });
  } catch (err) {
    return new Response('Invalid signature', { status: 400 });
  }

  // Handle events
  switch (evt.type) {
    case 'user.created':
      await handleUserCreated(evt.data);
      break;
    case 'user.updated':
      await handleUserUpdated(evt.data);
      break;
    case 'user.deleted':
      await handleUserDeleted(evt.data);
      break;
  }

  return new Response('OK');
}
```

---

## Supabase Integration

### Sync Users to Supabase

```typescript
// lib/clerk/sync-user.ts
import { createClient } from '@supabase/supabase-js';

async function handleUserCreated(userData: any) {
  const supabase = createClient(
    process.env.NEXT_PUBLIC_SUPABASE_URL!,
    process.env.SUPABASE_SERVICE_ROLE_KEY!
  );

  await supabase.from('profiles').insert({
    clerk_user_id: userData.id,
    email: userData.email_addresses[0].email_address,
    first_name: userData.first_name,
    last_name: userData.last_name,
    avatar_url: userData.image_url
  });
}
```

---

## Best Practices

### Custom Claims

```typescript
// Add custom claims in Clerk Dashboard or via API
const { sessionClaims } = auth();
const role = sessionClaims?.metadata?.role as string;

if (role !== 'admin') {
  return new Response('Forbidden', { status: 403 });
}
```

### Organizations

```typescript
import { auth } from '@clerk/nextjs';

const { orgId, orgRole } = auth();

if (!orgId) {
  redirect('/create-organization');
}

if (orgRole !== 'admin') {
  return <div>Admin access required</div>;
}
```

---

## References

- [Clerk Next.js Documentation](https://clerk.com/docs/nextjs)
- [Clerk API Reference](https://clerk.com/docs/reference/backend-api)
- [Webhooks Guide](https://clerk.com/docs/integrations/webhooks)

---

*MORPH-SPEC by Polymorphism Tech*
