# Clerk JavaScript SDKs Clerk is a complete authentication and user management platform for JavaScript applications. This monorepo contains the official Clerk JavaScript SDKs under the `@clerk` namespace, providing drop-in authentication UI components, session management, multi-tenancy with organizations, and a comprehensive backend API for managing users, sessions, and organizations programmatically. The SDK ecosystem supports multiple frameworks including Next.js, React, Express, Fastify, Hono, Astro, Vue, Nuxt, Expo, and more. It provides both client-side React components and hooks for building authentication flows, as well as server-side utilities for protecting routes, verifying sessions, and interacting with Clerk's Backend API. The architecture separates concerns into framework-specific packages that build upon shared core packages (`@clerk/backend`, `@clerk/shared`, `@clerk/clerk-js`). --- ## ClerkProvider Component The `ClerkProvider` component wraps your application and provides Clerk context to all child components. It must be placed at the root of your application to enable authentication features. ```tsx // app/layout.tsx (Next.js App Router) import { ClerkProvider } from '@clerk/nextjs'; export default function RootLayout({ children }: { children: React.ReactNode }) { return ( {children} ); } ``` --- ## clerkMiddleware (Next.js) The `clerkMiddleware()` function integrates Clerk authentication into Next.js applications through middleware. It handles session verification, protects routes, and provides authentication state to server components. ```typescript // middleware.ts import { clerkMiddleware } from '@clerk/nextjs/server'; // Basic usage - authenticates all requests export default clerkMiddleware(); // With route protection export default clerkMiddleware((auth, request) => { const { userId, sessionId } = auth(); // Protect specific routes if (request.nextUrl.pathname.startsWith('/dashboard')) { if (!userId) { return auth().redirectToSignIn(); } } // Protect with role-based access if (request.nextUrl.pathname.startsWith('/admin')) { auth().protect({ role: 'org:admin' }); } }); export const config = { matcher: ['/((?!.*\\..*|_next).*)', '/', '/(api|trpc)(.*)'], }; ``` --- ## auth() Function (Next.js Server) The `auth()` function retrieves the authentication state in Next.js server components, route handlers, and server actions. It provides access to the current user's session and includes helper methods for protecting resources. ```typescript // app/dashboard/page.tsx (Server Component) import { auth } from '@clerk/nextjs/server'; export default async function DashboardPage() { const { userId, sessionClaims, orgId, orgRole } = await auth(); if (!userId) { return
Please sign in to access the dashboard
; } return (

Welcome, User {userId}

Organization: {orgId || 'Personal account'}

Role: {orgRole || 'N/A'}

); } // app/api/protected/route.ts (Route Handler) import { auth } from '@clerk/nextjs/server'; import { NextResponse } from 'next/server'; export async function GET() { const { userId } = await auth(); if (!userId) { return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); } return NextResponse.json({ message: 'Protected data', userId }); } // Using auth.protect() for automatic protection export async function POST() { const { userId } = await auth.protect(); // Throws 401 if not authenticated // User is guaranteed to be authenticated here return NextResponse.json({ userId }); } ``` --- ## useAuth Hook The `useAuth()` hook provides access to the current user's authentication state and session management methods on the client side. It returns loading states, user identifiers, and utility functions for token retrieval. ```tsx 'use client'; import { useAuth } from '@clerk/nextjs'; export default function AuthStatus() { const { isLoaded, isSignedIn, userId, sessionId, orgId, orgRole, getToken, signOut, has } = useAuth(); if (!isLoaded) { return
Loading...
; } if (!isSignedIn) { return
Sign in to continue
; } const fetchProtectedData = async () => { const token = await getToken(); const response = await fetch('/api/protected', { headers: { Authorization: `Bearer ${token}` } }); return response.json(); }; // Check permissions const canManageUsers = has({ permission: 'org:users:manage' }); const isAdmin = has({ role: 'org:admin' }); return (

User ID: {userId}

Session ID: {sessionId}

Organization: {orgId || 'None'}

Can manage users: {canManageUsers ? 'Yes' : 'No'}

); } ``` --- ## useUser Hook The `useUser()` hook provides access to the current user's profile data including email addresses, phone numbers, profile image, and metadata. ```tsx 'use client'; import { useUser } from '@clerk/nextjs'; export default function UserProfile() { const { isLoaded, isSignedIn, user } = useUser(); if (!isLoaded) return
Loading...
; if (!isSignedIn) return
Not signed in
; return (
Profile

{user.fullName || user.username}

Email: {user.primaryEmailAddress?.emailAddress}

Phone: {user.primaryPhoneNumber?.phoneNumber}

Created: {user.createdAt?.toLocaleDateString()}

{/* Access user metadata */}

Role: {user.publicMetadata.role as string}

{/* Update user profile */}
); } ``` --- ## useOrganization Hook The `useOrganization()` hook provides access to the currently active organization's data, membership information, and management methods for multi-tenant applications. ```tsx 'use client'; import { useOrganization } from '@clerk/nextjs'; export default function OrganizationDashboard() { const { isLoaded, organization, membership, memberships, invitations, } = useOrganization({ memberships: { pageSize: 10 }, invitations: { pageSize: 5 }, }); if (!isLoaded) return
Loading...
; if (!organization) return
No organization selected
; return (
Org logo

{organization.name}

Slug: {organization.slug}

Your role: {membership?.role}

Members: {organization.membersCount}

Members

Pending Invitations

{/* Invite new member */}
); } ``` --- ## SignIn and SignUp Components Pre-built authentication components that provide complete sign-in and sign-up flows with customizable appearance and routing options. ```tsx // app/sign-in/[[...sign-in]]/page.tsx import { SignIn } from '@clerk/nextjs'; export default function SignInPage() { return ( ); } // app/sign-up/[[...sign-up]]/page.tsx import { SignUp } from '@clerk/nextjs'; export default function SignUpPage() { return ( ); } ``` --- ## UserButton Component A pre-built component that renders the current user's avatar and provides a dropdown menu for profile management, organization switching, and sign out. ```tsx 'use client'; import { UserButton } from '@clerk/nextjs'; export default function Header() { return (

My App

{/* Custom menu items */} } href="/settings" /> } onClick={() => openHelp()} />
); } ``` --- ## OrganizationSwitcher Component A pre-built component that allows users to switch between organizations and create new ones in multi-tenant applications. ```tsx 'use client'; import { OrganizationSwitcher } from '@clerk/nextjs'; export default function Sidebar() { return ( ); } ``` --- ## createClerkClient (Backend API) The `createClerkClient()` function creates a backend API client for server-side operations like user management, organization management, and session verification. ```typescript // lib/clerk.ts import { createClerkClient } from '@clerk/backend'; const clerkClient = createClerkClient({ secretKey: process.env.CLERK_SECRET_KEY, publishableKey: process.env.CLERK_PUBLISHABLE_KEY, }); // Get a user by ID const user = await clerkClient.users.getUser('user_123'); // List all users with pagination const { data: users, totalCount } = await clerkClient.users.getUserList({ limit: 10, offset: 0, orderBy: '-created_at', emailAddress: ['user@example.com'], }); // Create a new user const newUser = await clerkClient.users.createUser({ emailAddress: ['newuser@example.com'], password: 'securePassword123', firstName: 'John', lastName: 'Doe', publicMetadata: { role: 'customer' }, }); // Update user metadata await clerkClient.users.updateUserMetadata('user_123', { publicMetadata: { subscription: 'pro' }, privateMetadata: { stripeCustomerId: 'cus_xxx' }, }); // Ban/unban a user await clerkClient.users.banUser('user_123'); await clerkClient.users.unbanUser('user_123'); // Delete a user await clerkClient.users.deleteUser('user_123'); ``` --- ## Organization Management (Backend API) Backend API methods for managing organizations, memberships, invitations, and domains programmatically. ```typescript import { clerkClient } from '@clerk/nextjs/server'; // Create an organization const org = await clerkClient.organizations.createOrganization({ name: 'Acme Corp', slug: 'acme-corp', createdBy: 'user_123', // User who becomes admin maxAllowedMemberships: 100, publicMetadata: { plan: 'enterprise' }, }); // Get organization by ID or slug const organization = await clerkClient.organizations.getOrganization({ organizationId: 'org_123', includeMembersCount: true, }); // List organizations const { data: orgs } = await clerkClient.organizations.getOrganizationList({ limit: 10, query: 'acme', orderBy: '-created_at', }); // Manage memberships const membership = await clerkClient.organizations.createOrganizationMembership({ organizationId: 'org_123', userId: 'user_456', role: 'org:member', }); await clerkClient.organizations.updateOrganizationMembership({ organizationId: 'org_123', userId: 'user_456', role: 'org:admin', }); // List members const { data: members } = await clerkClient.organizations.getOrganizationMembershipList({ organizationId: 'org_123', limit: 50, role: ['org:admin'], }); // Send invitation const invitation = await clerkClient.organizations.createOrganizationInvitation({ organizationId: 'org_123', emailAddress: 'invite@example.com', role: 'org:member', inviterUserId: 'user_123', redirectUrl: 'https://myapp.com/accept-invite', }); // Revoke invitation await clerkClient.organizations.revokeOrganizationInvitation({ organizationId: 'org_123', invitationId: 'orginv_123', }); ``` --- ## Session Management (Backend API) Backend API methods for managing user sessions, including listing, revoking, and verifying sessions. ```typescript import { clerkClient } from '@clerk/nextjs/server'; // List all sessions for a user const { data: sessions } = await clerkClient.sessions.getSessionList({ userId: 'user_123', }); // Get a specific session const session = await clerkClient.sessions.getSession('sess_123'); // Revoke a session (sign out) await clerkClient.sessions.revokeSession('sess_123'); // Verify a session token import { verifyToken } from '@clerk/backend'; const verified = await verifyToken(sessionToken, { secretKey: process.env.CLERK_SECRET_KEY, authorizedParties: ['https://myapp.com'], }); console.log(verified.sub); // User ID console.log(verified.sid); // Session ID ``` --- ## verifyWebhook (Webhook Verification) The `verifyWebhook()` function verifies the authenticity of incoming Clerk webhooks using Svix signatures, ensuring webhook payloads haven't been tampered with. ```typescript // app/api/webhooks/clerk/route.ts import { verifyWebhook } from '@clerk/nextjs/webhooks'; import type { WebhookEvent } from '@clerk/nextjs/webhooks'; export async function POST(req: Request) { try { const evt = await verifyWebhook(req); // Handle different event types switch (evt.type) { case 'user.created': const { id, email_addresses, first_name } = evt.data; console.log(`New user: ${id}, ${email_addresses[0]?.email_address}`); // Create user in your database await db.user.create({ data: { clerkId: id, email: email_addresses[0]?.email_address, name: first_name, }, }); break; case 'user.updated': await db.user.update({ where: { clerkId: evt.data.id }, data: { name: evt.data.first_name }, }); break; case 'user.deleted': await db.user.delete({ where: { clerkId: evt.data.id }, }); break; case 'organization.created': console.log(`New org: ${evt.data.name}`); break; case 'organizationMembership.created': console.log(`User ${evt.data.public_user_data.user_id} joined org`); break; case 'session.created': console.log(`New session for user ${evt.data.user_id}`); break; } return new Response('Success', { status: 200 }); } catch (err) { console.error('Webhook verification failed:', err); return new Response('Webhook verification failed', { status: 400 }); } } ``` --- ## Express Integration The `@clerk/express` package provides middleware for protecting Express routes and accessing authentication state. ```typescript import 'dotenv/config'; import express from 'express'; import { clerkMiddleware, requireAuth, getAuth, clerkClient } from '@clerk/express'; const app = express(); // Apply Clerk middleware globally app.use(clerkMiddleware()); // Public route app.get('/', (req, res) => { res.json({ message: 'Welcome!' }); }); // Protected route using requireAuth middleware app.get('/protected', requireAuth(), (req, res) => { const { userId, sessionId } = getAuth(req); res.json({ message: 'Protected data', userId, sessionId }); }); // Check permissions app.get('/admin', requireAuth(), (req, res) => { const auth = getAuth(req); if (!auth.has({ role: 'org:admin' })) { return res.status(403).json({ error: 'Forbidden' }); } res.json({ message: 'Admin data' }); }); // Use backend API app.get('/users', requireAuth(), async (req, res) => { const users = await clerkClient.users.getUserList({ limit: 10 }); res.json({ users: users.data }); }); // Custom sign-in redirect app.get('/dashboard', requireAuth({ signInUrl: '/login' }), (req, res) => { res.json({ message: 'Dashboard' }); }); app.listen(3000, () => console.log('Server running on port 3000')); ``` --- ## useSignIn and useSignUp Hooks Hooks for building custom sign-in and sign-up flows with full control over the authentication process. ```tsx 'use client'; import { useSignIn, useSignUp } from '@clerk/nextjs'; import { useState } from 'react'; export function CustomSignIn() { const { isLoaded, signIn, setActive } = useSignIn(); const [email, setEmail] = useState(''); const [password, setPassword] = useState(''); const [error, setError] = useState(''); if (!isLoaded) return null; const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); try { const result = await signIn.create({ identifier: email, password, }); if (result.status === 'complete') { await setActive({ session: result.createdSessionId }); window.location.href = '/dashboard'; } else if (result.status === 'needs_second_factor') { // Handle 2FA } } catch (err: any) { setError(err.errors?.[0]?.message || 'Sign in failed'); } }; // OAuth sign-in const signInWithGoogle = () => { signIn.authenticateWithRedirect({ strategy: 'oauth_google', redirectUrl: '/sso-callback', redirectUrlComplete: '/dashboard', }); }; return (
setEmail(e.target.value)} placeholder="Email" /> setPassword(e.target.value)} placeholder="Password" /> {error &&

{error}

}
); } export function CustomSignUp() { const { isLoaded, signUp, setActive } = useSignUp(); const [email, setEmail] = useState(''); const [password, setPassword] = useState(''); const [verifying, setVerifying] = useState(false); const [code, setCode] = useState(''); const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); if (!isLoaded) return; try { await signUp.create({ emailAddress: email, password, }); // Send verification email await signUp.prepareEmailAddressVerification({ strategy: 'email_code' }); setVerifying(true); } catch (err: any) { console.error(err.errors?.[0]?.message); } }; const handleVerification = async (e: React.FormEvent) => { e.preventDefault(); if (!isLoaded) return; try { const result = await signUp.attemptEmailAddressVerification({ code }); if (result.status === 'complete') { await setActive({ session: result.createdSessionId }); window.location.href = '/welcome'; } } catch (err: any) { console.error(err.errors?.[0]?.message); } }; if (verifying) { return (
setCode(e.target.value)} placeholder="Verification code" />
); } return (
setEmail(e.target.value)} placeholder="Email" /> setPassword(e.target.value)} placeholder="Password" />
); } ``` --- ## Protect and Show Components Control components for conditionally rendering content based on authentication state and permissions. ```tsx import { SignedIn, SignedOut, Protect, RedirectToSignIn } from '@clerk/nextjs'; export default function ConditionalContent() { return (
{/* Show only when signed in */}

Welcome back! You are signed in.

{/* Show only when signed out */}

Please sign in to continue.

{/* Protect with role */} Admin access required

}>
{/* Protect with permission */} You don't have billing access

} >
{/* Protect with custom condition */} has({ role: 'org:admin' }) || has({ role: 'org:billing_manager' })} fallback={

Access denied

} >
{/* Redirect if not authenticated */}
); } ``` --- ## Testing with @clerk/testing The `@clerk/testing` package provides utilities for testing Clerk-authenticated applications with Playwright and Cypress. ```typescript // Playwright setup - playwright.config.ts import { clerkSetup } from '@clerk/testing/playwright'; import { defineConfig } from '@playwright/test'; export default defineConfig({ globalSetup: clerkSetup, use: { baseURL: 'http://localhost:3000', }, }); // Playwright test - tests/auth.spec.ts import { test, expect } from '@playwright/test'; import { clerk, setupClerkTestingToken } from '@clerk/testing/playwright'; test.beforeEach(async ({ page }) => { await setupClerkTestingToken({ page }); }); test('authenticated user can access dashboard', async ({ page }) => { await clerk.signIn({ page, signInParams: { strategy: 'password', identifier: 'test@example.com', password: 'testpassword123', }, }); await page.goto('/dashboard'); await expect(page.getByText('Welcome')).toBeVisible(); }); test('signed out user is redirected', async ({ page }) => { await clerk.signOut({ page }); await page.goto('/dashboard'); await expect(page).toHaveURL(/sign-in/); }); // Cypress setup - cypress/support/e2e.ts import { addClerkCommands } from '@clerk/testing/cypress'; addClerkCommands({ Cypress, cy }); // Cypress test - cypress/e2e/auth.cy.ts describe('Authentication', () => { beforeEach(() => { cy.clerkSignIn({ strategy: 'password', identifier: 'test@example.com', password: 'testpassword123', }); }); it('shows dashboard for authenticated users', () => { cy.visit('/dashboard'); cy.contains('Welcome').should('be.visible'); }); afterEach(() => { cy.clerkSignOut(); }); }); ``` --- Clerk provides a comprehensive solution for adding authentication to JavaScript applications across multiple frameworks. The primary use cases include implementing sign-in/sign-up flows with pre-built UI components, protecting API routes and pages, managing users and organizations programmatically through the backend API, and handling authentication-related webhooks. The SDK's modular architecture allows developers to use only the packages they need while maintaining consistent APIs across different frameworks. For integration patterns, Next.js applications typically use `clerkMiddleware()` for route protection and `auth()` for server-side authentication checks, while React applications rely on hooks like `useAuth()` and `useUser()` for client-side state. Backend services can use `createClerkClient()` directly for user management operations. The webhook system enables real-time synchronization between Clerk and your application's database, making it ideal for keeping user data in sync across systems. Multi-tenant applications benefit from the organization features, which provide built-in role-based access control and membership management.