Adding Clerk Authentication to a Full Stack Application with Django, FastAPI, and Next.js
How to add Clerk Authentication to our full stack app with Django, FastAPI and Next.js.
Adding Clerk Authentication to a Full Stack Application with Django, FastAPI, and Next.js
This tutorial extends the Full Stack Application with Django, FastAPI, and Next.js by integrating Clerk for user authentication and organization management. By the end you will have:
- Clerk-powered sign-in and sign-up pages in Next.js
- A signed webhook endpoint in FastAPI that syncs Clerk users and organizations into Django models
- PyJWT-based JWT verification so your FastAPI routes can authenticate calls from the frontend
- Django admin registration for the new models
Prerequisites: Docker Desktop installed and the base tutorial running locally (
docker compose up -dreturns no errors).
Steps
1. Set Up the Base Project
1.1 Clone the Original Tutorial Repository
1.2 Confirm Everything Runs
Open http://localhost and verify the default Next.js page loads before continuing.
2. Integrate Clerk with the Frontend
2.1 Create a Clerk Application
- Sign up or log in at clerk.com.
- Create a new application. Choose Email address + Google (or any providers you need).
- Leave the dashboard open โ you will copy API keys in ยง4.
2.2 Install Clerk in the Frontend
2.3 Rebuild the Frontend Image
2.4 Create Clerk Middleware
Clerk's clerkMiddleware() (introduced in @clerk/nextjs v5, replacing the older authMiddleware) makes authentication state available throughout your Next.js app. By default every route is public; you opt individual routes into protection inside the middleware callback.
Create frontend/src/middleware.ts:
Upgrading from v4? The old
authMiddlewarewas removed in@clerk/nextjsv5. Replace any existingauthMiddlewareusage withclerkMiddlewareas shown above.
2.5 Add ClerkProvider
Wrap your root layout with <ClerkProvider>. Edit frontend/src/app/layout.tsx:
2.6 Create Sign-In Page
Create frontend/src/app/sign-in/[[...sign-in]]/page.tsx:
2.7 Create Sign-Up Page
Create frontend/src/app/sign-up/[[...sign-up]]/page.tsx:
2.8 Add Sign-In / Sign-Out Buttons (Optional)
Add Clerk's prebuilt <UserButton> and <SignInButton> to your navbar or any server component:
3. Configure the FastAPI Backend for Clerk
3.1 Update Backend Dependencies
Edit backend/requirements.txt and add:
svix provides the webhook signature verification helper. PyJWT[crypto] (which pulls in cryptography) is needed to verify Clerk's RS256-signed session tokens on API requests.
Rebuild the backend services:
3.2 Create Schemas for Clerk Webhook
Edit backend/users/schemas.py:
3.3 Create a FastAPI Endpoint for the Clerk Webhook
Edit backend/users/routers.py:
Edit backend/mysaas/asgi.py to register the router:
3.4 Protect API Routes with Clerk JWT Verification
Clerk issues RS256-signed JWTs. Your frontend sends the token in an Authorization: Bearer <token> header. The FastAPI backend verifies it with the PEM public key available in your Clerk dashboard under API Keys โ Show JWT Public Key.
Add a reusable dependency in backend/users/auth.py:
Add CLERK_JWT_PUBLIC_KEY to backend/.env.local (paste the full PEM string):
Use the dependency in any protected route:
Frontend: sending the token
In a Next.js client component, use useAuth().getToken() to retrieve the JWT and pass it to your API:
4. Configure Clerk API Keys and Webhook
4.1 Set Up Clerk API Keys
- In the Clerk dashboard, go to Developers โ API Keys.
- Make sure the framework dropdown shows Next.js, then click Copy.
- Paste the values into
frontend/.env.local:
The redirect variables tell Clerk's components where to send users after authentication.
4.2 Set Up the Webhook Endpoint (Local Development with ngrok)
Install ngrok if needed, then expose your local port 80:
Copy the https:// hostname ngrok prints (e.g. https://7bc8-139-213-232-81.ngrok-free.app).
In the Clerk dashboard, go to Configure โ Webhooks โ Add Endpoint and enter:
Subscribe to all events under user, organization, and organizationMembership.
Click the ๐ icon next to Signing Secret and copy the value, then add it to backend/.env.local:
Production note: In production, use your real domain instead of an ngrok URL and make sure the
CLERK_WEBHOOK_SIGNING_SECRETis set in your deployment environment (e.g. as a Docker secret or platform environment variable). Never commit secrets to version control.
4.3 Set Up the JWT Public Key
In the Clerk dashboard, go to Developers โ API Keys โ Show JWT Public Key. Copy the PEM block and add it to backend/.env.local:
5. Update Backend Models and Admin
5.1 Update User Model
Edit backend/users/models.py:
5.2 Update Admin Interface
Edit backend/users/admin.py:
5.3 Create and Apply Migrations
6. Environment Variables Reference
Here is a complete summary of every environment variable used across the stack:
| Variable | File | Description |
|---|---|---|
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY | frontend/.env.local | Clerk publishable key (safe to expose) |
CLERK_SECRET_KEY | frontend/.env.local | Clerk secret key (keep private) |
NEXT_PUBLIC_CLERK_SIGN_IN_URL | frontend/.env.local | Path for the sign-in page |
NEXT_PUBLIC_CLERK_SIGN_UP_URL | frontend/.env.local | Path for the sign-up page |
NEXT_PUBLIC_CLERK_AFTER_SIGN_IN_URL | frontend/.env.local | Redirect after sign-in |
NEXT_PUBLIC_CLERK_AFTER_SIGN_UP_URL | frontend/.env.local | Redirect after sign-up |
CLERK_WEBHOOK_SIGNING_SECRET | backend/.env.local | Svix signing secret for webhook verification |
CLERK_JWT_PUBLIC_KEY | backend/.env.local | PEM public key for JWT verification on API routes |
7. Troubleshooting
Webhook returns 400 "Invalid webhook signature"
- Make sure ngrok is still running and the URL in the Clerk dashboard matches exactly (including the trailing slash).
- Confirm
CLERK_WEBHOOK_SIGNING_SECRETinbackend/.env.localmatches the secret shown in the Clerk dashboard. - Remember that ngrok free-tier URLs change every time you restart it โ update the Clerk dashboard URL each time.
authMiddleware not found after upgrading @clerk/nextjs
authMiddlewarewas removed in@clerk/nextjsv5. Replace it withclerkMiddlewareas shown in ยง2.4.
JWT verification fails on the API
- Verify the PEM key in
backend/.env.localincludes the full header and footer lines. - Newlines inside the PEM string in
.envfiles must be literal\nescape sequences or a multiline string. - Check that the token has not expired โ Clerk session tokens are short-lived by default.
Migrations fail
- Ensure the
usersapp is inINSTALLED_APPSinbackend/mysaas/settings.py. - Check that
clerk_iduniqueness constraints don't conflict with existing test data.
Damian Hodgkiss
Senior Staff Engineer at Sumo Group, leading development of AppSumo marketplace. Technical solopreneur with 25+ years of experience building SaaS products.