2

My setup is a SvelteKit app paired with an Express server (in order to handle sockets). This app has some POST requests which work fine with Vite, but not when I run it with Express. I get the error Cross-site POST form submissions are forbidden with a status code of 403 and a referrer policy "strict-origin-when-cross-origin".

So my question is very similar to this one, but the answers there didn't work for me (except for the insecure option to allow csrf). I also checked the SvelteKit documentation on the node adapter without success.

What I have tried:

  1. I added the variable ORIGIN=http://localhost:3000 node build/index.js to my .env file. I also added dotenv as a dependency and added dotenv.config() to my server file. But this has no effect.
  2. Setting csrf: {checkOrigin: false} in svelte.config.js fixed the issue, but this is not secure and not recommended.
  3. Running node -r dotenv/config build in the terminal. This prints out "Listening on 0.0.0.0:3000". But then my express server does not start at all. Perhaps the command needs to be added to the package.json, but I do not know where. There is no node build in the file.
  4. When I try to start my Express server with node -r dotenv/config server.js and open localhost:3000, I just get Invalid request body (code 400).

It sure is frustrating to setup websockets with SvelteKit, even after reading this blog post.

server.ts:

import express from "express";
import { handler } from "./build/handler.js";
import { attach_sockets } from "./sockets.js";
import dotenv from "dotenv";

dotenv.config();

const PORT = 3000;
const app = express();
const server = app.listen(PORT, () => {
    console.log("server is listening on port", PORT);
});
app.use(handler);

attach_sockets(server);
Script Raccoon
  • 261
  • 2
  • 14
  • 2
    If you are interested, I created an [adapter](https://www.npmjs.com/package/@carlosv2/adapter-node-ws) to easily work with websockets in SvelteKit. I'm currently using it in production without a problem but feel free to not use it if you don't feel like. As per the Cross-site issue, I also had the same issue and the `ORIGIN` variable fixed it. Make sure your variable is correctly loaded (try to print it, for example). Also try to build the project with this variable already set. – carlosV2 Mar 14 '23 at 22:25
  • 1
    @carlosV2 Thank you for the comment! I will check your adapter out. For now, I would like to tackle this issue here as well since it seems to be independent from sockets (maybe I should have made it more clear) - it happens everytime we use form actions and the node adapter, as far as I can tell. Now, regarding the .env file, it still does not work, can you point me to a repository where it works? Then I check what I made wrong. I also uploaded my code to GitHub (https://github.com/ScriptRaccoon/planning-poker), maybe you can check `server.ts` and `.env.example` (locally it's `.env`) there? – Script Raccoon Mar 15 '23 at 20:59
  • 1
    I pulled your code and tried to replicate your problem in local but I can't. However, I've taken a look at your `.env.example` and the variable there is incorrect. Because of the way you wrote your question, it looked like you added the variable to the command rather than that being its value. Try with `ORIGIN=http://localhost:3000` only. If this still does not work, please detail the steps I should take to replicate the error in local. – carlosV2 Mar 15 '23 at 23:11
  • Thank you! I also tried this var already, without success. Steps to reproduce: 1) npm install. 2) npm run build. 3) npm run start. 4) Open localhost:3000. 5) Go to /login and submit the login form. 6) This gives "Cross-site POST form submissions are forbidden". – Script Raccoon Mar 16 '23 at 07:10
  • 2
    Ok, managed to replicate it. I'll create an answer but I don't have good news :-( – carlosV2 Mar 16 '23 at 11:59

1 Answers1

3

I've taken a look at your code and I have good and bad news... the good news is that you did nothing wrong. The bad news is that you can't get it working because of the way SvelteKit and NodeJS works (at least not in the intended way).

Let me elaborate: From running your code, it is clear that the dotenv does not have any effect. Why is that? Quite simply, the .env file is loaded AFTER the ORIGIN value is requested by SvelteKit. This happens because you import the import { handler } from "./build/handler.js"; before running the dotenv.config();. Unfortunately, this module tries to resolve the ORIGIN immediately during import so there isn't much we can do here.... but, before you jump into changing the order, keep reading.

The second issue you have is that NodeJS runs the import statements first so, even if you swap the lines so that the .env file is loaded before the import, it still would not work.

So, what solution can we apply here? There are 2 options we can take: either inject the variable into the process without an .env file and then run the code or import the .env file and then run the code.

In order to inject the variable before running the code you need to run your code like this:

ORIGIN=http://localhost:3000 node server.js

This time, this line is a command you need to run. If you run this line, you don't need the .env file (although it is not harmful and you can leave it if you have other variables).

Instead, if you want to import the .env file completely, you need to run the command like this instead:

NODE_OPTIONS='-r dotenv/config' node server.js

At least you can update your package.json to include those changes in the start script so that you can continue using npm run start as an alias.

carlosV2
  • 1,167
  • 6
  • 15
  • Thanks a lot for this great answer! I already tried to run `ORIGIN=http://localhost:3000 node server.js` before asking here, but since I am on Windows right now and used the command line, this throws an error ("ORIGIN" is no known command). But in Git Bash it works fine (also under Windows), and the post request works, yay! I will try if this works as the start command in production as well (probably not!), but maybe you already know what needs to be adjusted there? – Script Raccoon Mar 16 '23 at 20:32
  • I'm afraid I haven't used a windows machine for almost 20 years so I'm not entirely sure how to help you here. I remember you could inject environment variables by doing something on "My PC" but I'm not sure if this is still available. I have [found this](https://stackoverflow.com/questions/3036325/can-i-set-an-environment-variable-for-an-application-using-a-shortcut-in-windows) which is similar to bash so you could try. Regarding your prod environment, do you also run windows there? Alternatively, I heard windows has the WSL which seems quite promising but I haven't tried it. – carlosV2 Mar 17 '23 at 09:49
  • 1
    Thanks! I just deployed the app, and here the start command needs to be "ORIGIN={the live url} node server.js". Everything seems to work :-). – Script Raccoon Mar 18 '23 at 21:52
  • FYI - I was having issues with env variables in the package.json file for our app - I am on Windows, everyone else is on Mac. There is a package called cross-env that allows us to set variables no matter the OS: in package.json: alias: cross-env ENV_VAR=whatever – Justin Greywolf May 24 '23 at 15:49