# 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
);
}
```
---
## 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 (
{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
);
}
```
---
## 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 (
);
}
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 (
);
}
return (
);
}
```
---
## 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.