fix: allow custom Clerk frontend API domain in CSP (NEXT_PUBLIC_CLERK_FAPI_HOST)
Some checks are pending
CI / build (push) Waiting to run

This commit is contained in:
dimitar 2026-08-03 19:43:28 +02:00
parent 2af9c823fb
commit 89b1dc9a51
3 changed files with 25 additions and 4 deletions

View File

@ -13,6 +13,7 @@ RUN apk add --no-cache openssl
# them via build args (Coolify: mark them as build variables) or the browser
# ClerkProvider / public URLs will be missing.
ARG NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY
ARG NEXT_PUBLIC_CLERK_FAPI_HOST
ARG NEXT_PUBLIC_CLERK_SIGN_IN_URL
ARG NEXT_PUBLIC_CLERK_SIGN_UP_URL
ARG NEXT_PUBLIC_CLERK_SIGN_IN_FALLBACK_REDIRECT_URL

View File

@ -108,6 +108,9 @@ DATABASE_URL=postgresql://postgres:YOUR_PASSWORD@spomeniqr-db:5432/monuments
# Clerk
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_live_...
CLERK_SECRET_KEY=sk_live_...
# Custom Clerk frontend API domain (if configured in Clerk dashboard) — the CSP
# allowlist needs it. Build variable. Omit if not using a custom domain.
NEXT_PUBLIC_CLERK_FAPI_HOST=clerk.testbed.mk
NEXT_PUBLIC_CLERK_SIGN_IN_URL=/sign-in
NEXT_PUBLIC_CLERK_SIGN_UP_URL=/sign-up
NEXT_PUBLIC_CLERK_SIGN_IN_FALLBACK_REDIRECT_URL=/
@ -148,7 +151,10 @@ NODE_ENV=production
node -e "import('bcryptjs').then(b => b.default.hash('YOUR_PASSWORD', 12).then(console.log))"
```
- Mark **every `NEXT_PUBLIC_*` variable as a build variable** (checkbox) so it is
inlined into the client bundle at `next build`. Server-only vars
inlined into the client bundle at `next build` and visible to `next.config.ts`.
`NEXT_PUBLIC_CLERK_FAPI_HOST` in particular must be a build variable — the CSP
is generated at build time and will otherwise block Clerk JS if you use a
custom Clerk frontend API domain. Server-only vars
(`CLERK_SECRET_KEY`, `DATABASE_URL`, `ADMIN_SESSION_SECRET`,
`SUPER_ADMIN_PASSWORD_HASH`, `S3_*`) stay as normal runtime variables.
- The `super` admin row is provisioned automatically on container start by
@ -344,6 +350,7 @@ npx prisma db push
|----------|----------|-------------|
| `DATABASE_URL` | Yes | PostgreSQL connection string (Coolify internal) |
| `NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY` | Yes | Clerk publishable key (`pk_live_...`) |
| `NEXT_PUBLIC_CLERK_FAPI_HOST` | No* | Custom Clerk frontend API domain (`clerk.testbed.mk`) — required when using a custom domain; build variable |
| `CLERK_SECRET_KEY` | Yes | Clerk secret key (`sk_live_...`) |
| `NEXT_PUBLIC_CLERK_SIGN_IN_URL` | Yes | `/sign-in` |
| `NEXT_PUBLIC_CLERK_SIGN_UP_URL` | Yes | `/sign-up` |

View File

@ -4,9 +4,12 @@ const s3Host = process.env.S3_ENDPOINT
? new URL(process.env.S3_ENDPOINT).hostname
: "";
// Derive the Clerk frontend API host from the publishable key so the
// CSP allowlist always matches the active environment. Clerk supports
// two publishable key formats:
// Derive the Clerk frontend API host so the CSP allowlist always matches the
// active environment. When a custom Clerk frontend API domain is configured in
// the Clerk dashboard (e.g. clerk.testbed.mk), it is resolved at runtime by
// clerk-js and can NOT be derived from the publishable key — so it must be
// provided explicitly via NEXT_PUBLIC_CLERK_FAPI_HOST. Otherwise Clerk
// supports two publishable key formats:
//
// 1) "Encoded" form (older): pk_test_<base64slug>$
// The base64 portion decodes to "<slug>.clerk.accounts.dev" (test)
@ -17,6 +20,16 @@ const s3Host = process.env.S3_ENDPOINT
// The slug may itself contain hyphens and digits, so only the
// final dash-group is captured as the suffix.
function clerkFrontendApiHost(): string | null {
const custom = process.env.NEXT_PUBLIC_CLERK_FAPI_HOST?.trim();
if (custom) {
try {
const host = new URL(custom.includes("://") ? custom : `https://${custom}`).hostname;
if (host) return host;
} catch {
// fall through to derivation from the publishable key
}
}
const key = process.env.NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY;
if (!key) return null;