Go to file
dimitar 59988a597e fix(csp): whitelist Clerk frontend API host derived from publishable key
The Phase 3 CSP was too strict for Clerk and blocked its browser-side
runtime. Reported runtime error:

  ClerkRuntimeError: Failed to load Clerk JS, failed to load script:
  https://useful-louse-74.clerk.accounts.dev/npm/@clerk/clerk-js@6/
  dist/clerk.browser.js (code='failed_to_load_clerk_js')

Root cause: script-src allowed only 'self' 'unsafe-inline' 'unsafe-
eval', so the browser blocked the Clerk JS bundle fetched from the
per-instance frontend-API host. The connect-src allowlist of
'*.clerk.accounts.dev' was also both too narrow (no production
*.clerk.services host, no real FAPI host on the actual subdomain)
and hard-coded — it didn't track changes in the publishable key.

Fix:
- next.config.ts now derives the active Clerk frontend-API host from
  NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY at build time:
    pk_test_<slug>-<suffix>  -> <slug>.clerk.accounts.dev
    pk_live_<slug>-<suffix>  -> <slug>.clerk.services
  The slug itself may contain digits and hyphens, so the suffix is
  captured as the final dash-group (regex: ^pk_(test|live)_(.+?)-
  ([a-z0-9]+)$). Verified against the user's actual key
  'pk_test_useful-louse-74-O42m8W' -> 'useful-louse-74.clerk.accounts.dev'.
- script-src now includes https://<fapiHost> so Clerk can pull its
  browser bundle from <fapiHost>/npm/@clerk/clerk-js@<v>/dist/...
- connect-src now includes https://<fapiHost> + wss://<fapiHost>
  for Clerk's session/socket traffic.
- img-src now whitelists https://img.clerk.com (Clerk-served user
  avatars) and keeps the open 'https:' for memorial images that
  we proxy through our own /api/image.
- remotePatterns in next/image now lists img.clerk.com alongside
  the dynamic S3 host, so next/image (if/when adopted) will accept
  Clerk avatar URLs.
- If the publishable key is absent, the FAPI host simply isn't
  added to either directive, so dev without Clerk configured stays
  functional.

The build emits the exact right CSP for the active environment
without any hand-editing when promoting test -> live.
2026-08-02 20:39:15 +02:00
.github/workflows chore(devops): Phase 5 — Dockerfile, .dockerignore, CI, deploy cleanup, error/loading UI 2026-08-02 13:20:10 +02:00
docs docs: Phase 7 — reconcile drift, delete scratch, rewrite admin.md 2026-08-02 15:15:50 +02:00
prisma feat(schema): Phase 6 — VarChar bounds, updatedAt, key index, prisma seed 2026-08-02 14:47:41 +02:00
public init 2026-06-20 18:17:30 +02:00
scripts feat(security): Phase 1 — harden auth, rate limiting, CSRF, upload validation 2026-08-02 10:24:28 +02:00
src chore(devops): Phase 5 — Dockerfile, .dockerignore, CI, deploy cleanup, error/loading UI 2026-08-02 13:20:10 +02:00
.dockerignore chore(devops): Phase 5 — Dockerfile, .dockerignore, CI, deploy cleanup, error/loading UI 2026-08-02 13:20:10 +02:00
.env.example feat(security): Phase 1 — harden auth, rate limiting, CSRF, upload validation 2026-08-02 10:24:28 +02:00
.gitignore chore(devops): Phase 5 — Dockerfile, .dockerignore, CI, deploy cleanup, error/loading UI 2026-08-02 13:20:10 +02:00
docker-compose.dev.yaml local dev setup 2026-07-29 16:52:54 +02:00
docker-compose.yaml t v3 2026-06-22 23:28:41 +02:00
Dockerfile chore(devops): Phase 5 — Dockerfile, .dockerignore, CI, deploy cleanup, error/loading UI 2026-08-02 13:20:10 +02:00
Dockerfile.dev local dev setup 2026-07-29 16:52:54 +02:00
eslint.config.mjs init 2026-06-20 18:17:30 +02:00
next.config.ts fix(csp): whitelist Clerk frontend API host derived from publishable key 2026-08-02 20:39:15 +02:00
package-lock.json feat(schema): Phase 6 — VarChar bounds, updatedAt, key index, prisma seed 2026-08-02 14:47:41 +02:00
package.json feat(schema): Phase 6 — VarChar bounds, updatedAt, key index, prisma seed 2026-08-02 14:47:41 +02:00
postcss.config.mjs init 2026-06-20 18:17:30 +02:00
tsconfig.json test: Phase 4 — vitest setup + unit tests for admin-session and rate-limit 2026-08-02 13:05:06 +02:00
vitest.config.ts test: Phase 4 — vitest setup + unit tests for admin-session and rate-limit 2026-08-02 13:05:06 +02:00

This is a Next.js project bootstrapped with create-next-app.

Getting Started

First, run the development server:

npm run dev
# or
yarn dev
# or
pnpm dev
# or
bun dev

Open http://localhost:3000 with your browser to see the result.

You can start editing the page by modifying app/page.tsx. The page auto-updates as you edit the file.

This project uses next/font to automatically optimize and load Geist, a new font family for Vercel.

Learn More

To learn more about Next.js, take a look at the following resources:

You can check out the Next.js GitHub repository - your feedback and contributions are welcome!

Deploy on Vercel

The easiest way to deploy your Next.js app is to use the Vercel Platform from the creators of Next.js.

Check out our Next.js deployment documentation for more details.