Go to file
dimitar dd0dd9c2dc
Some checks are pending
CI / build (push) Waiting to run
fix(csp): handle base64-encoded Clerk publishable keys
Investigation with the running container revealed the previous fix
was correct on the deployed server but didn't help the user because
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY in their .env has the placeholder
'pk_test_...' from .env.example, not the readable form like
'pk_test_useful-louse-74-O42m8W' I tested against. The actual key is
in Clerk's older "encoded" format:

  pk_test_dXNlZnVsLWxvdXNlLTc0LmNsZXJrLmFjY291bnRzLmRldiQ

The base64 portion decodes to the literal FAPI host
'useful-louse-74.clerk.accounts.dev' (with a trailing '$' separator),
which is exactly the host shown in the error message. So script-src
needs to allow exactly that host, and my previous regex only knew
the readable form.

clerkFrontendApiHost() now handles both formats:

  Form 1 (encoded): pk_test_<base64slug>\$
                    /-> decode b64 /-> <slug>.clerk.accounts.dev
                                   (or .clerk.services for ?)
                    Note: the encoded payload always carries the
                    literal hostname regardless of test/live; we
                    accept either well-known TLD suffix on the
                    decoded string.

  Form 2 (readable): pk_test_<slug>-<randomSuffix>
                    /-> <slug>.clerk.accounts.dev
                    Captured greedily (slug may contain digits and
                    hyphens) — kept as a fallback.

Defensive fall-throughs ensure a string that decodes to garbage
(e.g. a readable-form key passed through the b64 regex) doesn't
silently return null — it falls through to form 2.

Verified against four cases:
  pk_test_dXNlZnVsLWxvdXNlLTc0...     -> useful-louse-74.clerk.accounts.dev ✓
  pk_test_useful-louse-74-O42m8W      -> useful-louse-74.clerk.accounts.dev ✓
  pk_live_dXNlZnVsLWxvdXNlLTc0...     -> useful-louse-74.clerk.accounts.dev ✓
  pk_test_invalid-garbage             -> invalid.clerk.accounts.dev (form 2)

The user must rebuild and redeploy for the new CSP header to take
effect — the previously-served header is cached in the running
container's standalone bundle and won't refresh until container
restart with the new build.
2026-08-02 21:42:53 +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): handle base64-encoded Clerk publishable keys 2026-08-02 21:42:53 +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.