CORS Error: What is the correct way to configure Symfony 5 to accept CORS?

Viewed 7489

Objective

I'm attempting to send a request from a Vue 3 typescript frontend to a Symfony 5 API. Using the NelmioCorsBundle The request is working in Insommia (postman) but is not working in Chrome, Safari and Firefox.

The Error

Access to fetch at 'https://localhost:8000/api/users/6' from origin 'http://localhost:8080' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

Request on the front end (Vue):

import { onMounted, ref } from 'vue'
import { useStore } from 'vuex'

export default {
  name: 'Home',
  setup () {
    const message = ref('Please login...')
    const store = useStore()

    onMounted(async () => {
      try {
        const response = await fetch('https://localhost:8000/api/users/6', {
          headers: { 'Content-Type': 'application/json' },
          credentials: 'include'
        })

        console.log(response)
        const user = await response.json()
        message.value = `Hello ${user.name}`
        await store.dispatch('setAuth', true)
      } catch (e) {
        console.log(e)
      }
      return {
        message
      }
    })
  }
}

NelmioCorsBundle config in Symfony:

nelmio_cors:
    defaults:
        origin_regex: true
        allow_origin: ['%env(CORS_ALLOW_ORIGIN)%']
        allow_methods: ['GET', 'OPTIONS', 'POST', 'PUT', 'PATCH', 'DELETE']
        allow_headers: ['Content-Type', 'Authorization']
        expose_headers: ['Link']
        max_age: 3600
    paths:
        '^/': null

in the .env file the CORS_ALLOW_ORIGIN is defined so:

CORS_ALLOW_ORIGIN='^http?://(localhost|127\.0\.0\.1)(:[0-9]+)?$'

My Attempts

  1. I have tried setting the Access-Control-Allow-Origin header in the NelmioCorsBundle and in the index.php
  2. I have tried 'http://localhost:8080' as the allow_origin.
  3. I tried pragmatically setting different headers in the index.php file, just ended up going down an error rabbit hole.
  4. I also tried the documention's recommendation on How to ignore preflight requests on New Relic? This FilterResponseEvent class didn't exist (so reinstalled the NelmioCorsBundle, to no effect.)
3 Answers

After struggling with nelmio for a while, I found it easier to go with this ghetto solution:

public/index.php:

if ($_SERVER['APP_DEBUG']) {
    header('Access-Control-Allow-Origin:'.rtrim($_SERVER['HTTP_REFERER'], '/'));
} else {
    header('Access-Control-Allow-Origin:yourdomain');
}
header('Access-Control-Allow-Headers:*');
header('Access-Control-Allow-Credentials:true');
header('Access-Control-Allow-Headers:X-Requested-With, Content-Type, withCredentials');
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
    die();
}

I use this just after the bootEnv line. I'm using symfony 5+

Hi this it works fine and the frontend I was using axios with ReactJs.

nelmio_cors.yaml

nelmio_cors:
    defaults:
        origin_regex: true
        allow_origin: ['*']
        allow_methods: ['GET', 'OPTIONS', 'POST', 'PUT', 'PATCH', 'DELETE']
        allow_headers: ['*']
        expose_headers: ['Link']
        max_age: 3600
    paths:
        '^/': ~

.env

###> nelmio/cors-bundle ###
CORS_ALLOW_ORIGIN=^.*$
###< nelmio/cors-bundle ###

Hi could you try changing the path from '^/' to '^/api/' in NelmioCorsBundle and add this configuration like this example:

nelmio_cors:
    defaults:
        origin_regex: true
        allow_origin: ['%env(CORS_ALLOW_ORIGIN)%']
        allow_methods: ['GET', 'OPTIONS', 'POST', 'PUT', 'PATCH', 'DELETE']
        allow_headers: ['Content-Type', 'Authorization']
        expose_headers: ['Link']
        max_age: 3600
    paths:
        '^/api/':
            allow_origin: ['%env(CORS_ALLOW_ORIGIN)%']
            allow_headers: ['X-Custom-Auth', 'Content-Type', 'Authorization', 'Location']
            allow_methods: ['POST', 'PUT', 'GET', 'DELETE', 'OPTION']
            expose_headers: ['Link', 'Location']
            max_age: 3600
Related