Clerk Dashboard Setup Guide — Archived
Clerk Dashboard Setup Guide — Archived
⚠️ Archived: Clerk integration has been fully removed from the codebase. Better Auth is the active and only supported auth provider. Re-enabling Clerk would require reintroducing Clerk-related code (middleware, routes, env vars, etc.), not just setting environment variables. This document is retained for historical reference only.
See Better Auth User Guide and Configuration Guide for current setup instructions.
(see auth-provider-selection.md).
This guide walks you through creating and configuring a Clerk application for the bloqr-backend.
Prerequisites
- A Clerk account (free tier is sufficient to start)
- Access to your Cloudflare Workers dashboard
- The bloqr-backend deployed (or running locally)
Step 1: Create a Clerk Application
- Sign in to dashboard.clerk.com
- Click “Add application”
- Enter your application name (e.g.,
Bloqr Compiler) - Choose your sign-in options:
- Recommended: Email address + Google OAuth
- Optional: GitHub, Apple, or other social providers
- Click “Create application”
Step 2: Get Your API Keys
After creating the application, navigate to API Keys in the sidebar:
| Key | Where to Use | Example Format |
|---|---|---|
| Publishable Key | Worker env (CLERK_PUBLISHABLE_KEY) | pk_test_... or pk_live_... |
| Secret Key | Worker env (CLERK_SECRET_KEY) — never expose | sk_test_... or sk_live_... |
Important: The publishable key is safe to expose publicly. The secret key must be stored as a Cloudflare Worker secret.
Step 3: Configure URLs
Navigate to Paths (under “Configure” in sidebar):
Sign-in and Sign-up URLs
| Setting | Value |
|---|---|
| Sign-in URL | /sign-in |
| Sign-up URL | /sign-up |
| After sign-in URL | /compiler |
| After sign-up URL | /compiler |
Allowed Origins
Under Domains → Allowed origins, add:
https://your-worker.workers.devhttps://your-custom-domain.comhttp://localhost:4200 (for Angular dev server)http://localhost:8787 (for Wrangler local dev)Step 4: Configure JWT Templates (Optional)
By default, Clerk JWTs include standard claims. To include tier information in the JWT:
- Go to JWT Templates in the sidebar
- Click “New template” → “Blank”
- Name it
bloqr-backend - Add custom claims:
{ "metadata": "{{user.public_metadata}}"}This ensures the user’s tier (set in public metadata) is available in the JWT payload, reducing database lookups.
Note: If you don’t configure a JWT template, the system will look up the user’s tier from the database on each request. Both approaches work; the JWT template approach is more performant.
Step 5: Configure Webhooks
Webhooks sync user data between Clerk and your Cloudflare D1 database.
- Go to Webhooks in the sidebar
- Click “Add Endpoint”
- Configure:
| Setting | Value |
|---|---|
| Endpoint URL | https://your-worker.workers.dev/api/webhooks/clerk |
| Message Filtering | Select: user.created, user.updated, user.deleted |
- Click “Create”
- Copy the Signing Secret (starts with
whsec_...)
Important: Store the signing secret as
CLERK_WEBHOOK_SECRETin your Worker secrets.
Testing Webhooks
Clerk provides a “Testing” tab on each webhook endpoint:
- Select an event type (e.g.,
user.created) - Click “Send test webhook”
- Check the delivery log for a
200response
Webhook Events Handled
| Event | Action | Database Effect |
|---|---|---|
user.created | Create/update user record | Insert into users table |
user.updated | Update user profile/tier | Update users table |
user.deleted | Delete user | Hard-delete from users table |
Step 6: Set User Tiers via Public Metadata
User tiers are stored in Clerk’s public metadata. To set a user’s tier:
Via Clerk Dashboard
- Go to Users in the sidebar
- Click on a user
- Scroll to Public metadata
- Click “Edit” and set:
{ "tier": "pro", "role": "user"}Available Tiers
| Tier Value | Numeric Order | Description |
|---|---|---|
anonymous | 0 | Unauthenticated (system-assigned) |
free | 1 | Default for new signups |
pro | 2 | Paid subscriber |
admin | 3 | Full admin access |
Via Clerk Backend API
curl -X PATCH https://api.clerk.com/v1/users/{user_id}/metadata \ -H "Authorization: Bearer sk_live_..." \ -H "Content-Type: application/json" \ -d '{ "public_metadata": { "tier": "pro", "role": "user" } }'Tip: When a user’s tier is updated via the API or dashboard, Clerk fires a
user.updatedwebhook, which automatically syncs the change to your Cloudflare D1 database.
Step 7: Configure Environment Variables
Local Development — Use direnv/.env.local (recommended)
This project uses direnv + .envrc for local env management. Add your Clerk keys to .env.local (gitignored):
# .env.local (copy from .env.example, then fill in your real values)CLERK_PUBLISHABLE_KEY=pk_test_...CLERK_SECRET_KEY=sk_test_...CLERK_JWKS_URL=https://your-instance.clerk.accounts.dev/.well-known/jwks.jsonCLERK_WEBHOOK_SECRET=whsec_...Run direnv allow once in the repo root to activate automatic loading.
Production Deployment — Use wrangler secret put
For Cloudflare Workers production deployments, store all Clerk variables as Worker secrets:
# All Clerk variables (use prod pk_live_ / sk_live_ keys)wrangler secret put CLERK_PUBLISHABLE_KEYwrangler secret put CLERK_SECRET_KEYwrangler secret put CLERK_JWKS_URLwrangler secret put CLERK_WEBHOOK_SECRETFinding Your JWKS URL
- Go to API Keys in the Clerk dashboard
- Note the Frontend API URL (e.g.,
https://abc-123.clerk.accounts.dev) - Append
/.well-known/jwks.json - Full URL:
https://abc-123.clerk.accounts.dev/.well-known/jwks.json
Step 8: Test the Integration
Verify JWT Authentication
# 1. Sign in via the frontend to get a Clerk session# 2. Copy the JWT from browser DevTools (Application → Cookies → __session)# 3. Test an authenticated endpoint:
curl -X GET https://your-worker.workers.dev/api/keys \ -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIs..."Verify Webhook Delivery
- Create a test user in Clerk dashboard
- Check your Worker logs for webhook processing
- Verify the user appears in your D1
userstable:
# Query via Wrangler (remote D1)wrangler d1 execute bloqr-backend-app-db --remote \ --command="SELECT id, email, tier, clerk_user_id FROM users ORDER BY created_at DESC LIMIT 5;"Verify Public Metadata Tier
- Set a user’s tier to
adminin Clerk dashboard - Sign in as that user
- Access an admin endpoint — should succeed
- Sign in as a
freeuser — admin endpoints should return 403
Troubleshooting
”Invalid JWT” Errors
- Verify
CLERK_JWKS_URLis correct and accessible - Ensure the JWT hasn’t expired (default lifetime: 60 seconds)
- Check that the Clerk instance is in the correct mode (test vs. live)
“Webhook signature verification failed”
- Verify
CLERK_WEBHOOK_SECRETmatches the signing secret in Clerk dashboard - Ensure the webhook endpoint URL exactly matches (including trailing slash behavior)
- Check that the Svix headers (
svix-id,svix-timestamp,svix-signature) are being forwarded
”User not found” After Sign-Up
- Verify the
user.createdwebhook is configured and delivering - Check Worker logs for webhook processing errors
- Manually trigger a test webhook from the Clerk dashboard
JWT Template Not Applied
- Ensure the JWT template name matches what the frontend requests via
getToken({ template: 'bloqr-backend' }) - If no template is specified, Clerk returns a default JWT without custom claims
Security Checklist
-
CLERK_SECRET_KEYstored as Worker secret (not inwrangler.toml) -
CLERK_WEBHOOK_SECRETstored as Worker secret - Allowed origins configured for all deployment URLs
- Test mode (
pk_test_) keys NOT used in production - Webhook endpoint only accepts POST requests
- JWKS URL is correct and accessible from Workers
- Admin users have
tier: "admin"in public metadata - CF Access configured for admin routes (optional but recommended)
Step 9: Deploy to Cloudflare Workers
This section walks through deploying the full Clerk integration to a Cloudflare Worker from scratch.
Prerequisites
- Wrangler CLI installed and authenticated (
wrangler login) - A Cloudflare account with Workers and D1 enabled
- Clerk API keys from Steps 2 and 5 above
9a. Apply the D1 Migration
The users table (used by the Clerk webhook handler) lives in Cloudflare D1. Apply the migration to the remote D1 database before deploying:
# Apply the Clerk users migration to the remote D1 databasewrangler d1 migrations apply bloqr-backend-app-db --remoteVerify the table was created:
wrangler d1 execute bloqr-backend-app-db --remote \ --command="SELECT name FROM sqlite_master WHERE type='table';"You should see users (and other D1 tables) in the output.
9b. Set Worker Secrets
Store all secrets via Wrangler’s secret management — never commit real keys to wrangler.toml:
# Clerk authentication secretswrangler secret put CLERK_SECRET_KEYwrangler secret put CLERK_WEBHOOK_SECRETWhen prompted, paste the corresponding values from your Clerk dashboard.
9c. Add Public Variables to wrangler.toml
CLERK_PUBLISHABLE_KEY and CLERK_JWKS_URL are public (non-secret) values that belong in wrangler.toml [vars]:
[vars]CLERK_PUBLISHABLE_KEY = "pk_live_..." # from Clerk Dashboard → API KeysCLERK_JWKS_URL = "https://<instance>.clerk.accounts.dev/.well-known/jwks.json"Note: For local development, put these in
.env.local(loaded by direnv) rather thanwrangler.toml.
9d. Deploy the Worker
# Using the project task (runs preflight checks first)deno task wrangler:deploy
# Or directly with Wranglerwrangler deployAfter deployment, confirm the worker is live:
curl https://your-worker.workers.dev/api/version9e. Update the Webhook Endpoint URL
Back in the Clerk Dashboard:
- Go to Webhooks → your endpoint
- Update the Endpoint URL to your production Worker URL:
https://your-worker.workers.dev/api/webhooks/clerk
- Click Save
If you previously used a local dev URL (e.g., from wrangler dev or Cloudflare Tunnel), remove it and add only the production URL.
9f. Verify End-to-End
Test webhook delivery:
- In the Clerk Dashboard, go to Webhooks → your endpoint → Testing tab
- Select
user.createdand click Send test webhook - The delivery log should show a
200 OKresponse - Confirm the user appeared in D1:
wrangler d1 execute bloqr-backend-app-db --remote \ --command="SELECT id, email, tier FROM users ORDER BY created_at DESC LIMIT 3;"Test JWT authentication:
# Sign in via the Angular frontend, then copy the session token from# browser DevTools (Application → Cookies → __session) and test:curl https://your-worker.workers.dev/api/keys \ -H "Authorization: Bearer <your-clerk-jwt>"9g. Switch to Production Keys
When ready to go live, replace test keys with production keys:
# Update the secret with the sk_live_ keywrangler secret put CLERK_SECRET_KEY # paste sk_live_...And in wrangler.toml:
[vars]CLERK_PUBLISHABLE_KEY = "pk_live_..." # was pk_test_...Reminder: After changing
wrangler.toml, redeploy withwrangler deploy.