How to call webhook triggered flow from frontend (avoid CORS errors)

Hi everyone, I’m mixing n8n with custom frontend software to interface with the flows and I’m wondering how I can set the access-control-allow-origin in pre-flight to whitelist certain domains so that I can call n8n from frontend code?

Is this even possible currently?

1 Like

Hey @chrisgereina!

Does adding the cross-origin header in the Header parameters of the request help? I will try to recreate the issue and get back to you with a solution :slight_smile:

Hey, are you making POST requests or is it a GET request?

It’s a POST request

I looked at the code for one of my projects that does something similar. In the browser console, I do get an error, but my workflow gets executed successfully. I am not certain why this is happening. One thing that I did was remove any header parameters from the request. For some reason, passing header parameters was not allowing the workflow to execute.

I will continue to debug this and get share my solution here.

Thank you @harshil1712!

Hey, this might not be a possible solution for you but if it’s a simple request with minimum functionality then setting Request.mode - Web APIs | MDN (mozilla.org) to no-cors could be something that might help you.

The catch being for it is explained nicely at javascript - What limitations apply to opaque responses? - Stack Overflow. Another solution could be setting up a reverse proxy using something like the cors-anywhere project by Rob Wu. (Can’t link since new user limitations) :sweat_smile:

3 Likes

Hello :slight_smile:
I had the same issue the last days and just fixed it a few hours ago with the following Settings, problem is that Frontend (Your Project) and API (n8n) have to be one same domain for easiest cors requirements.

Frontend: yourdomain.org
Backend (n8n): yourdomain.org/api

docker-compose.yml

version: “3”
services:
traefik:
image: “traefik”
restart: always
command:
- “–api=true”
- “–api.insecure=true”
- “–api.dashboard=true”
- “–providers.docker=true”
- “–providers.docker.exposedbydefault=false”
- “–entrypoints.websecure.address=:443”
- “–certificatesresolvers.mytlschallenge.acme.tlschallenge=true”
- “–certificatesresolvers.mytlschallenge.acme.email=${SSL_EMAIL}”
- “–certificatesresolvers.mytlschallenge.acme.storage=/letsencrypt/acme.json”
ports:
- “443:443”

    volumes:
      - ${DATA_FOLDER}/letsencrypt:/letsencrypt
      - /var/run/docker.sock:/var/run/docker.sock:ro
  n8n:
    image: n8nio/n8n
    restart: always
    ports:
      - "127.0.0.1:5678:5678"       
    labels:
      - traefik.enable=true
      - traefik.http.routers.n8n.rule=Host(`${DOMAIN_NAME}`)
      - traefik.http.routers.n8n.tls=true
      - traefik.http.routers.n8n.entrypoints=websecure
      - "traefik.http.routers.n8n.rule=PathPrefix(`/${SUBFOLDER}{regex:$$|/.*}`)"
      - "traefik.http.middlewares.n8n-stripprefix.stripprefix.prefixes=/${SUBFOLDER}"
      - "traefik.http.routers.n8n.middlewares=n8n-stripprefix"
      - traefik.http.routers.n8n.tls.certresolver=mytlschallenge
      - traefik.http.middlewares.n8n.headers.SSLRedirect=true
      - traefik.http.middlewares.n8n.headers.STSSeconds=315360000
      - traefik.http.middlewares.n8n.headers.browserXSSFilter=true
      - traefik.http.middlewares.n8n.headers.contentTypeNosniff=true
      - traefik.http.middlewares.n8n.headers.forceSTSHeader=true
      - traefik.http.middlewares.n8n.headers.SSLHost=${DOMAIN_NAME}
      - traefik.http.middlewares.n8n.headers.STSIncludeSubdomains=true
      - traefik.http.middlewares.n8n.headers.STSPreload=true
    environment:         
      - N8N_BASIC_AUTH_ACTIVE=false
      - N8N_BASIC_AUTH_USER
      - N8N_BASIC_AUTH_PASSWORD
      - N8N_HOST=${DOMAIN_NAME}
      - N8N_PORT=5678
      - N8N_PROTOCOL=http
      - NODE_ENV=production
      - N8N_PATHs
      - WEBHOOK_TUNNEL_URL=https://${DOMAIN_NAME}${N8N_PATH}
      - VUE_APP_URL_BASE_API=https://${DOMAIN_NAME}${N8N_PATH}
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - ${DATA_FOLDER}/.n8n:/root/.n8n
    command: /bin/sh -c "sleep 5; n8n start"

Matching nginx conf

server {
listen 80;
server_name your.domain;
location / {
root /app; #/app directory is where html files are placed
index index.html;
try_files $uri $uri/ /index.html; #router history mode enable
}
location /api #yoursubpath as you like {

          rewrite ^/api/(.*)$ /$1 break;
          proxy_set_header Accept-Encoding "";
          proxy_pass http://127.0.0.1:5678; #n8n resolves
          proxy_set_header Connection '';
          proxy_http_version 1.1;
          chunked_transfer_encoding off;
          proxy_buffering off;
          proxy_cache off;      
        }
        
    #uncomment below to lock the worflow UI of n8n (only webhooks and flows enabled)
        #location ^~ /api {
                #return 404;
            #} 
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
          root   /usr/share/nginx/html; #Your error/404 Page
        }
    }    

n8n .env

    # Folder where data should be saved
    DATA_FOLDER=/root/n8n-sub/
    # The top level domain to serve from
    DOMAIN_NAME=localhost
    # The subfolder to serve from
    #Same as the path in nginx conf
    SUBFOLDER=api
    N8N_PATH=/api/
    # The user name to use for autentication - IMPORTANT ALWAYS CHANGE!
    N8N_BASIC_AUTH_USER=user
    # The password to use for autentication - IMPORTANT ALWAYS CHANGE!
    N8N_BASIC_AUTH_PASSWORD=password
    # Optional timezone to set which gets used by Cron-Node by default
    # If not set New York time will be used
    GENERIC_TIMEZONE=Europe/Berlin
    # The email address to use for the SSL certificate creation
    [email protected]

Good luck @chrisgereina

3 Likes

@harshil1712 are there any plans to configure an allow list for n8n or is this something that is actually something that needs to be handled at the traefik level?

Hey @chrisgereina!

Can you please elaborate on what list you’re talking about?

I did some tests and found out that I get the CORS errors when I try to send header parameters with the body. If no header parameters are sent, the request is successfully received by n8n. I tried the solution shared by @Amorpheuz, and that worked well in my case.

@harshil1712 a proxy definitely works and it’s what I’m using right now to get around the issue, but CORS itself is the browser’s way of telling whether or not a request is authorized for a resource on a server, the browser takes its cues from the server response as to whether or not the calling computer (or origin) is allowed to make a request on the server.

Unless you’re making the request from the same domain (origin) like @leadandconversion mentioned you’d have to specifically list the origin as allowed in the server so that when the browser requests the resource it sees that it should be let through - what I was asking above is if there’s some way to configure that in n8n or if you think that’s actually something that would have to be handled by traefik since it sits in front of n8n?

Update: have been using @Amorpheuz solution with no-cors but it has a built-in problem when getting responses, namely that it doesn’t let the browser see the response at all by design

Here are two stackoverflow questions to that effect

The key part being:

A no-cors request makes the response type opaque . The log snippet in the question shows that. Opaque means your frontend JavaScript code can’t see the response body or headers.

@harshil1712 one of the suggested solutions is as follows:

I imagine you’re trying no-cors because the response from http://localhost:8080/course doesn’t include the Access-Control-Allow-Origin response header or else because your request is one that triggers a CORS preflight, and so your browser does an OPTIONS preflight.

But using no-cors mode is not the solution to those problems. The solution is to configure the http://localhost:8080 server to send the Access-Control-Allow-Origin response header and to handle the OPTIONS request

@harshil1712 is there any way for us to configure the Access-Control-Allow-Origin response header as suggested in the stackoverflow answer?

1 Like

@harshil1712 just bumping this up in case it got buried in the notifications

Hey @chrisgereina, sorry I missed it. I am not sure how to handle this. If you want to do it via a reverse proxy, you might have to look into its documentation.

@jan can we configure it in n8n?

Add axios proxy to avoid CORS problems
This seems to work perfectly

nuxt.config.js`

modules: [
    ...
    "@nuxtjs/proxy",
  ],

axios: { proxy: true },

proxy: {
  "/api/": {
    target: "https://api.url.you.want/to/proxy",
    pathRewrite: { "^/api/": "" },
    changeOrigin: true,
  },
},

After this you can make a request throw the proxy. Be sure you are using “/api/” in your call as base url

await this.$axios
  .$post("/api/my-endpoint")
  .then((result) => {
    console.log(result);
  })
  .catch((err) => {
    console.log(err);
  });

@chrisgereina I hope it works for you

@jan would you happen to know of a good workaround for this? This keeps causing problems, unfortunately. I’m currently using Nuxt with a proxy as @rogelio94 suggested and although it works fine locally when I deploy it statically proxying is a no-go.

It would be nice if we could somehow get the server to whitelist a given domain so that we can make requests from a browser without getting CORS issues

1 Like

I’ve created a proper feature request for adding CORS to n8n webhooks here:

1 Like