diff --git a/apps/api/app/webhooks/clerk/route.ts b/apps/api/app/webhooks/clerk/route.ts
index 2432f28c..c52fa07c 100644
--- a/apps/api/app/webhooks/clerk/route.ts
+++ b/apps/api/app/webhooks/clerk/route.ts
@@ -1,11 +1,11 @@
+import { analytics } from '@repo/analytics/posthog/server';
import type {
DeletedObjectJSON,
OrganizationJSON,
OrganizationMembershipJSON,
UserJSON,
WebhookEvent,
-} from '@clerk/nextjs/server';
-import { analytics } from '@repo/analytics/posthog/server';
+} from '@repo/auth/server';
import { env } from '@repo/env';
import { log } from '@repo/observability/log';
import { headers } from 'next/headers';
diff --git a/apps/api/app/webhooks/stripe/route.ts b/apps/api/app/webhooks/stripe/route.ts
index 7c2053b7..f2ec7ee7 100644
--- a/apps/api/app/webhooks/stripe/route.ts
+++ b/apps/api/app/webhooks/stripe/route.ts
@@ -1,5 +1,5 @@
-import { clerkClient } from '@clerk/nextjs/server';
import { analytics } from '@repo/analytics/posthog/server';
+import { clerkClient } from '@repo/auth/server';
import { env } from '@repo/env';
import { parseError } from '@repo/observability/error';
import { log } from '@repo/observability/log';
diff --git a/apps/api/package.json b/apps/api/package.json
index 59a5ab37..402be2b0 100644
--- a/apps/api/package.json
+++ b/apps/api/package.json
@@ -10,8 +10,8 @@
"stripe": "stripe listen --forward-to localhost:3002/webhooks/stripe"
},
"dependencies": {
- "@clerk/nextjs": "^6.3.4",
"@repo/analytics": "workspace:*",
+ "@repo/auth": "workspace:*",
"@repo/database": "workspace:*",
"@repo/design-system": "workspace:*",
"@repo/env": "workspace:*",
diff --git a/apps/app/app/(authenticated)/components/posthog-identifier.tsx b/apps/app/app/(authenticated)/components/posthog-identifier.tsx
index 05222da8..1d0e1bee 100644
--- a/apps/app/app/(authenticated)/components/posthog-identifier.tsx
+++ b/apps/app/app/(authenticated)/components/posthog-identifier.tsx
@@ -1,7 +1,7 @@
'use client';
-import { useUser } from '@clerk/nextjs';
import { analytics } from '@repo/analytics/posthog/client';
+import { useUser } from '@repo/auth/client';
import { usePathname, useSearchParams } from 'next/navigation';
import { useEffect, useRef } from 'react';
diff --git a/apps/app/app/(authenticated)/components/sidebar.tsx b/apps/app/app/(authenticated)/components/sidebar.tsx
index 5515accf..2297448c 100644
--- a/apps/app/app/(authenticated)/components/sidebar.tsx
+++ b/apps/app/app/(authenticated)/components/sidebar.tsx
@@ -1,6 +1,6 @@
'use client';
-import { OrganizationSwitcher, UserButton } from '@clerk/nextjs';
+import { OrganizationSwitcher, UserButton } from '@repo/auth/client';
import { ModeToggle } from '@repo/design-system/components/mode-toggle';
import {
Collapsible,
diff --git a/apps/app/app/(authenticated)/layout.tsx b/apps/app/app/(authenticated)/layout.tsx
index e4124088..d2b6264f 100644
--- a/apps/app/app/(authenticated)/layout.tsx
+++ b/apps/app/app/(authenticated)/layout.tsx
@@ -1,4 +1,4 @@
-import { auth, currentUser } from '@clerk/nextjs/server';
+import { auth, currentUser } from '@repo/auth/server';
import { SidebarProvider } from '@repo/design-system/components/ui/sidebar';
import { showBetaFeature } from '@repo/feature-flags';
import arcjet, { detectBot, request } from '@repo/security';
diff --git a/apps/app/app/(authenticated)/page.tsx b/apps/app/app/(authenticated)/page.tsx
index 12e35907..55137ccf 100644
--- a/apps/app/app/(authenticated)/page.tsx
+++ b/apps/app/app/(authenticated)/page.tsx
@@ -1,4 +1,4 @@
-import { auth } from '@clerk/nextjs/server';
+import { auth } from '@repo/auth/server';
import { database } from '@repo/database';
import {
Breadcrumb,
diff --git a/apps/app/app/actions/users/get.ts b/apps/app/app/actions/users/get.ts
index 22529ca7..ca8bae65 100644
--- a/apps/app/app/actions/users/get.ts
+++ b/apps/app/app/actions/users/get.ts
@@ -4,7 +4,7 @@ import {
type OrganizationMembership,
auth,
clerkClient,
-} from '@clerk/nextjs/server';
+} from '@repo/auth/server';
import { tailwind } from '@repo/tailwind-config';
const getName = (user: OrganizationMembership): string | undefined => {
diff --git a/apps/app/app/actions/users/search.ts b/apps/app/app/actions/users/search.ts
index 8cda661d..c25d8abc 100644
--- a/apps/app/app/actions/users/search.ts
+++ b/apps/app/app/actions/users/search.ts
@@ -4,7 +4,7 @@ import {
type OrganizationMembership,
auth,
clerkClient,
-} from '@clerk/nextjs/server';
+} from '@repo/auth/server';
import Fuse from 'fuse.js';
const getName = (user: OrganizationMembership): string | undefined => {
diff --git a/apps/app/app/api/collaboration/auth/route.ts b/apps/app/app/api/collaboration/auth/route.ts
index 817618ec..b4d726f4 100644
--- a/apps/app/app/api/collaboration/auth/route.ts
+++ b/apps/app/app/api/collaboration/auth/route.ts
@@ -1,4 +1,4 @@
-import { auth, currentUser } from '@clerk/nextjs/server';
+import { auth, currentUser } from '@repo/auth/server';
import { authenticate } from '@repo/collaboration/auth';
import { tailwind } from '@repo/tailwind-config';
diff --git a/apps/app/middleware.ts b/apps/app/middleware.ts
index d2840231..e37a24e2 100644
--- a/apps/app/middleware.ts
+++ b/apps/app/middleware.ts
@@ -1,6 +1,6 @@
-import { clerkMiddleware } from '@clerk/nextjs/server';
+import { authMiddleware } from '@repo/auth/middleware';
-export default clerkMiddleware();
+export default authMiddleware();
export const config = {
matcher: [
diff --git a/apps/app/package.json b/apps/app/package.json
index bebd73f4..b65bff5a 100644
--- a/apps/app/package.json
+++ b/apps/app/package.json
@@ -9,7 +9,6 @@
"test": "vitest run"
},
"dependencies": {
- "@clerk/nextjs": "^6.3.4",
"@prisma/client": "5.22.0",
"@repo/auth": "workspace:*",
"@repo/analytics": "workspace:*",
diff --git a/apps/web/middleware.ts b/apps/web/middleware.ts
index c37858f9..133242e8 100644
--- a/apps/web/middleware.ts
+++ b/apps/web/middleware.ts
@@ -1,4 +1,4 @@
-import { clerkMiddleware } from '@clerk/nextjs/server';
+import { authMiddleware } from '@repo/auth/middleware';
import arcjet, { detectBot } from '@repo/security';
import { NextResponse } from 'next/server';
@@ -21,7 +21,7 @@ const aj = arcjet.withRule(
})
);
-export default clerkMiddleware(async (_auth, request) => {
+export default authMiddleware(async (_auth, request) => {
const decision = await aj.protect(request);
if (
diff --git a/apps/web/package.json b/apps/web/package.json
index 6f554c12..4a900b92 100644
--- a/apps/web/package.json
+++ b/apps/web/package.json
@@ -10,7 +10,6 @@
},
"dependencies": {
"@arcjet/next": "1.0.0-alpha.28",
- "@clerk/nextjs": "^6.3.4",
"@content-collections/mdx": "^0.2.0",
"@radix-ui/react-icons": "^1.3.2",
"@repo/design-system": "workspace:*",
diff --git a/docs/authentication/authjs.mdx b/docs/authentication/authjs.mdx
new file mode 100644
index 00000000..0d80188f
--- /dev/null
+++ b/docs/authentication/authjs.mdx
@@ -0,0 +1,132 @@
+---
+title: Switch to Auth.js
+description: How to switch from Clerk to Auth.js.
+---
+
+
+next-forge support for Auth.js is currently blocked by [this issue](https://github.com/nextauthjs/next-auth/issues/11076).
+
+
+Here's how to switch from Clerk to [Auth.js](https://authjs.dev/).
+
+## 1. Replace the dependencies
+
+Uninstall the existing Clerk dependencies from the `auth` package...
+
+```sh Terminal
+pnpm remove @clerk/nextjs @clerk/themes @clerk/types --filter auth
+```
+
+... and install the Auth.js dependencies.
+
+```sh Terminal
+pnpm add next-auth@beta --filter auth
+```
+
+## 2. Generate an Auth.js secret
+
+Auth.js requires a random value secret, used by the library to encrypt tokens and email verification hashes. In each of the relevant app directories, generate a secret with the following command:
+
+```sh Terminal
+cd apps/app && npx auth secret
+cd apps/web && npx auth secret
+cd apps/api && npx auth secret
+```
+
+This will automatically add an `AUTH_SECRET` environment variable to the `.env.local` file in each directory.
+
+## 3. Replace the relevant files
+
+Delete the existing `client.ts` and `server.ts` files in the `auth` package. Then, create the following file:
+
+```tsx packages/auth/index.ts
+import NextAuth from "next-auth";
+
+export const { handlers, signIn, signOut, auth } = NextAuth({
+ providers: [],
+});
+```
+
+## 4. Update the middleware
+
+Update the `middleware.ts` file in the `auth` package with the following content:
+
+```tsx packages/auth/middleware.ts
+import 'server-only';
+
+export { auth as authMiddleware } from './';
+```
+
+## 5. Update the auth components
+
+Auth.js has no concept of "sign up", so we'll use the `signIn` function to sign up users. Update both the `sign-in.tsx` and `sign-up.tsx` components in the `auth` package with the same content:
+
+
+
+```tsx packages/auth/components/sign-in.tsx
+import { signIn } from '../';
+
+export const SignIn = () => (
+
+);
+```
+
+```tsx packages/auth/components/sign-up.tsx
+import { signIn } from '../';
+
+export const SignUp = () => (
+
+);
+```
+
+
+
+## 6. Update the Provider file
+
+Auth.js has no concept of a Provider as a higher-order component, so you can either remove it entirely or just replace it with a stub, like so:
+
+```tsx packages/auth/provider.tsx
+import type { ReactNode } from 'react';
+
+type AuthProviderProps = {
+ children: ReactNode;
+};
+
+export const AuthProvider = ({ children }: AuthProviderProps) => children;
+```
+
+## 7. Create an auth route handler
+
+In your `app` application, create an auth route handler file with the following content:
+
+```tsx apps/app/api/auth/[...nextauth]/route.ts
+import { handlers } from "@repo/auth"
+
+export const { GET, POST } = handlers;
+```
+
+## 8. Update your apps
+
+From here, you'll need to replace any remaining Clerk implementations in your apps with Auth.js references. This means swapping out references like:
+
+```tsx page.tsx
+const { orgId } = await auth();
+const { redirectToSignIn } = await auth();
+const user = await currentUser();
+```
+
+Etcetera. Keep in mind that you'll need to build your own "organization" logic as Auth.js doesn't have a concept of organizations.
diff --git a/docs/authentication.mdx b/docs/authentication/overview.mdx
similarity index 80%
rename from docs/authentication.mdx
rename to docs/authentication/overview.mdx
index 80762648..dee2e2c1 100644
--- a/docs/authentication.mdx
+++ b/docs/authentication/overview.mdx
@@ -1,9 +1,9 @@
---
-title: Authentication
+title: Overview
description: We use Clerk to handle authentication, user and organization management.
---
-[Clerk](https://clerk.com/) is used for authentication in next-forge. Clerk provides a complete authentication and user management solution that integrates seamlessly with Next.js applications.
+next-forge manages authentication through the use of a `auth` package. By default, this package is a wrapper around [Clerk](https://clerk.com/) which provides a complete authentication and user management solution that integrates seamlessly with Next.js applications.
## In-App
diff --git a/docs/mint.json b/docs/mint.json
index 2e4feb4d..d4bcd9e0 100644
--- a/docs/mint.json
+++ b/docs/mint.json
@@ -53,7 +53,10 @@
"group": "Analytics",
"pages": ["analytics/web", "analytics/product"]
},
- "authentication",
+ {
+ "group": "Authentication",
+ "pages": ["authentication/overview", "authentication/authjs"]
+ },
"blog",
"bundle-analysis",
"collaboration",
diff --git a/packages/auth/client.ts b/packages/auth/client.ts
new file mode 100644
index 00000000..a832599f
--- /dev/null
+++ b/packages/auth/client.ts
@@ -0,0 +1 @@
+export * from '@clerk/nextjs';
diff --git a/packages/auth/middleware.ts b/packages/auth/middleware.ts
new file mode 100644
index 00000000..9d816d0e
--- /dev/null
+++ b/packages/auth/middleware.ts
@@ -0,0 +1 @@
+export { clerkMiddleware as authMiddleware } from '@clerk/nextjs/server';
diff --git a/packages/auth/package.json b/packages/auth/package.json
index 0e09b814..becd85fa 100644
--- a/packages/auth/package.json
+++ b/packages/auth/package.json
@@ -7,7 +7,8 @@
"@clerk/themes": "^2.1.45",
"@repo/tailwind-config": "workspace:*",
"next-themes": "^0.4.3",
- "react": "^18.3.1"
+ "react": "^18.3.1",
+ "server-only": "^0.0.1"
},
"devDependencies": {
"@clerk/types": "^4.34.0",
diff --git a/packages/auth/server.ts b/packages/auth/server.ts
new file mode 100644
index 00000000..73ec4ca8
--- /dev/null
+++ b/packages/auth/server.ts
@@ -0,0 +1,3 @@
+import 'server-only';
+
+export * from '@clerk/nextjs/server';
diff --git a/packages/feature-flags/lib/create-flag.ts b/packages/feature-flags/lib/create-flag.ts
index 89ef9f77..0015b651 100644
--- a/packages/feature-flags/lib/create-flag.ts
+++ b/packages/feature-flags/lib/create-flag.ts
@@ -1,5 +1,5 @@
-import { auth } from '@clerk/nextjs/server';
import { analytics } from '@repo/analytics/posthog/server';
+import { auth } from '@repo/auth/server';
import { unstable_flag as flag } from '@vercel/flags/next';
export const createFlag = (key: string) =>
diff --git a/packages/feature-flags/package.json b/packages/feature-flags/package.json
index 86d5a502..31748302 100644
--- a/packages/feature-flags/package.json
+++ b/packages/feature-flags/package.json
@@ -3,7 +3,7 @@
"version": "0.0.0",
"private": true,
"dependencies": {
- "@clerk/nextjs": "^6.3.4",
+ "@repo/auth": "workspace:*",
"@repo/analytics": "workspace:*",
"@repo/design-system": "workspace:*",
"@vercel/flags": "^2.6.3"
diff --git a/packages/webhooks/lib/svix.ts b/packages/webhooks/lib/svix.ts
index c4aa7856..ddc77f8e 100644
--- a/packages/webhooks/lib/svix.ts
+++ b/packages/webhooks/lib/svix.ts
@@ -1,5 +1,5 @@
import 'server-only';
-import { auth } from '@clerk/nextjs/server';
+import { auth } from '@repo/auth/server';
import { env } from '@repo/env';
import { Svix } from 'svix';
diff --git a/packages/webhooks/package.json b/packages/webhooks/package.json
index 60becaba..8184f46c 100644
--- a/packages/webhooks/package.json
+++ b/packages/webhooks/package.json
@@ -3,8 +3,8 @@
"version": "0.0.0",
"private": true,
"dependencies": {
+ "@repo/auth": "workspace:*",
"@repo/env": "workspace:*",
- "@clerk/nextjs": "^6.3.4",
"svix": "^1.40.0"
},
"devDependencies": {
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 27aa266f..f1408ef0 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -32,12 +32,12 @@ importers:
apps/api:
dependencies:
- '@clerk/nextjs':
- specifier: ^6.3.4
- version: 6.3.4(next@15.0.3(@opentelemetry/api@1.9.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@repo/analytics':
specifier: workspace:*
version: link:../../packages/analytics
+ '@repo/auth':
+ specifier: workspace:*
+ version: link:../../packages/auth
'@repo/database':
specifier: workspace:*
version: link:../../packages/database
@@ -93,9 +93,6 @@ importers:
apps/app:
dependencies:
- '@clerk/nextjs':
- specifier: ^6.3.4
- version: 6.3.4(next@15.0.3(@opentelemetry/api@1.9.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@prisma/client':
specifier: 5.22.0
version: 5.22.0(prisma@5.22.0)
@@ -239,9 +236,6 @@ importers:
'@arcjet/next':
specifier: 1.0.0-alpha.28
version: 1.0.0-alpha.28(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.6.1(@bufbuild/protobuf@1.10.0))(next@15.0.3(@opentelemetry/api@1.9.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))
- '@clerk/nextjs':
- specifier: ^6.3.4
- version: 6.3.4(next@15.0.3(@opentelemetry/api@1.9.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@content-collections/mdx':
specifier: ^0.2.0
version: 0.2.0(@content-collections/core@0.7.3(typescript@5.6.3))(acorn@8.13.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
@@ -406,6 +400,9 @@ importers:
react:
specifier: ^18.3.1
version: 18.3.1
+ server-only:
+ specifier: ^0.0.1
+ version: 0.0.1
devDependencies:
'@clerk/types':
specifier: ^4.34.0
@@ -742,12 +739,12 @@ importers:
packages/feature-flags:
dependencies:
- '@clerk/nextjs':
- specifier: ^6.3.4
- version: 6.3.4(next@15.0.1(@opentelemetry/api@1.9.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@repo/analytics':
specifier: workspace:*
version: link:../analytics
+ '@repo/auth':
+ specifier: workspace:*
+ version: link:../auth
'@repo/design-system':
specifier: workspace:*
version: link:../design-system
@@ -922,9 +919,9 @@ importers:
packages/webhooks:
dependencies:
- '@clerk/nextjs':
- specifier: ^6.3.4
- version: 6.3.4(next@15.0.3(@opentelemetry/api@1.9.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ '@repo/auth':
+ specifier: workspace:*
+ version: link:../auth
'@repo/env':
specifier: workspace:*
version: link:../env
@@ -8507,20 +8504,6 @@ snapshots:
react-dom: 18.3.1(react@18.3.1)
tslib: 2.4.1
- '@clerk/nextjs@6.3.4(next@15.0.1(@opentelemetry/api@1.9.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
- dependencies:
- '@clerk/backend': 1.16.4(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
- '@clerk/clerk-react': 5.15.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
- '@clerk/shared': 2.14.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
- '@clerk/types': 4.34.0
- crypto-js: 4.2.0
- ezheaders: 0.1.0(next@15.0.1(@opentelemetry/api@1.9.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))
- next: 15.0.1(@opentelemetry/api@1.9.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
- react: 18.3.1
- react-dom: 18.3.1(react@18.3.1)
- server-only: 0.0.1
- tslib: 2.4.1
-
'@clerk/nextjs@6.3.4(next@15.0.3(@opentelemetry/api@1.9.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
dependencies:
'@clerk/backend': 1.16.4(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
@@ -12401,10 +12384,6 @@ snapshots:
iconv-lite: 0.4.24
tmp: 0.0.33
- ezheaders@0.1.0(next@15.0.1(@opentelemetry/api@1.9.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)):
- dependencies:
- next: 15.0.1(@opentelemetry/api@1.9.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
-
ezheaders@0.1.0(next@15.0.3(@opentelemetry/api@1.9.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)):
dependencies:
next: 15.0.3(@opentelemetry/api@1.9.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)