0

I have a SvelteKit app running at http://localhost:5173 (when doing local development) with a Nginx in front of it running at http://localhost:8057, serving some static files and proxying requests that must be handled by SvelteKit.

I have a login form at http://localhost:8057/login and when I submit it I get a web page with just "Cross-site POST form submissions are forbidden".

I tried using the ORIGIN environment variable as per Cross-site POST form submissions are forbidden and https://kit.svelte.dev/docs/adapter-node#environment-variables. Here is my .env file:

ORIGIN=http://localhost:8057

I can see this environment variable in my environment if I log env from import { env } from '$env/dynamic/private'; in the server side. But I still get "Cross-site POST form submissions are forbidden".

I also tried passing the environement variable when starting SvelteKit (with ORIGIN=http://localhost:8057 npm run dev), but same result.

Because SvelteKit does not log much when it sends this error I can just try to guess what's going on inside SvelteKit, but if in Nginx I add proxy_set_header Origin http://localhost:5173; then it works, so it's pretty clear what origin SvelteKit expects here. I'd rather not do this however because it is pretty much equivalent to disabling CSRF protection.

I then tried to use the other method suggested in https://kit.svelte.dev/docs/adapter-node#environment-variables, that is, to use x-forwarded-proto and x-forwarded-host, so now here is my .env file (and again I can definitely see these values if I log them in my app):

PROTOCOL_HEADER=x-forwarded-proto
HOST_HEADER=x-forwarded-host
ORIGIN=http://localhost:8057

and in my Nginx configuration (the same place where replacing the Origin header would fix everything):

location @sveltekit {
  proxy_pass http://localhost:5173;
  proxy_set_header X-Real-IP $remote_addr;
  proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  proxy_set_header X-Forwarded-Proto $scheme;
  proxy_set_header X-Forwarded-Host $host;
}

And I still get "Cross-site POST form submissions are forbidden". Any idea what else I could try?

In case people want to see or run the code:

Cédric Van Rompay
  • 2,489
  • 1
  • 18
  • 24

1 Answers1

4

The problem was coming from that I was in dev mode (npm run dev) and that the PROTOCOL_HEADER, HOST_HEADER and ORIGIN environment variables documented in https://kit.svelte.dev/docs/adapter-node#environment-variables work for the node adapter (which is used when you do npm run build when targeting NodeJS) but not for the Vite dev server.

The message "Cross-site POST form submissions are forbidden" comes from packages/kit/src/runtime/server/respond.js which is not tied to the node adapter, it runs whatever adapter you're using. What is misleading is that if you search about this error message you'll only read about it in a context that's related to the NodeJS adapter, like https://kit.svelte.dev/docs/adapter-node#environment-variables.

The "solution" you read about in this context is to use the PROTOCOL_HEADER, HOST_HEADER and ORIGIN environment variables, but these are only understood by the node adapter. You can see them being used in packages/adapter-node/src/handler.js.

When you run your SvelteKit app with npm run dev you're not using the NodeJS adapter. You are using the Vite development server, which does not read these environment variables. You can see how this development server sets the "origin" of the request in packages/kit/src/exports/vite/dev/index.js. It only uses the "host" header of the request but ignores any "x-forwarded-host" or other similar headers.

One solution is to make your proxy set the "host" HTTP header. Don't do this in production, but in dev mode this should be OK. Another is to disable CSRF protection in dev mode.

There is already an issue in SvelteKit's GitHub repository about this: https://github.com/sveltejs/kit/issues/8026

Cédric Van Rompay
  • 2,489
  • 1
  • 18
  • 24