markhuot / craftql

A drop-in GraphQL server for Craft CMS
Other
320 stars 53 forks source link

CORS issue because of multiple values inside 'Access-Control-Allow-Origin' returned from craftql #316

Closed Jones-S closed 5 years ago

Jones-S commented 5 years ago

Maybe this is a bug?

I am getting an error like:

Access to fetch at 'https://cms.mypage.ch/api' from origin 'http://localhost:3000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: The 'Access-Control-Allow-Origin' header contains multiple values 'localhost:3000, *', but only one is allowed. Have the server send the header with a valid value, or, if an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

I think this is happening somewhere here:

craftql/src/Controllers/ApiController.php around line 71.

$response = \Craft::$app->getResponse();
        if ($allowedOrigins = CraftQL::getInstance()->getSettings()->allowedOrigins) {
            if (is_string($allowedOrigins)) {
                $allowedOrigins = [$allowedOrigins];
            }
            $origin = \Craft::$app->getRequest()->headers->get('Origin');
            if (in_array($origin, $allowedOrigins) || in_array('*', $allowedOrigins)) {
                $response->headers->set('Access-Control-Allow-Origin', $origin);
            }
            $response->headers->set('Access-Control-Allow-Credentials', 'true');
            $response->headers->set('Access-Control-Allow-Headers', implode(', ', CraftQL::getInstance()->getSettings()->allowedHeaders));
        }
        $response->headers->set('Allow', implode(', ', CraftQL::getInstance()->getSettings()->verbs));

Why is it sending multiple headers, and how could I stop it to do that, to prevent a CORS issue on my site?

If somebody could share his thoughts, that would be great. cheers

PS: the same is happening if my remote (not localhost) site is accessing the API.

Jones-S commented 5 years ago

If I change the ApiController to:

$response = \Craft::$app->getResponse();
        if ($allowedOrigins = CraftQL::getInstance()->getSettings()->allowedOrigins) {
            if (is_string($allowedOrigins)) {
                $allowedOrigins = [$allowedOrigins];
            }
            $origin = \Craft::$app->getRequest()->headers->get('Origin');
            $response->headers->set('Access-Control-Allow-Origin', 'yolo');
            // if (in_array($origin, $allowedOrigins) || in_array('*', $allowedOrigins)) {
            // }
            $response->headers->set('Access-Control-Allow-Credentials', 'true');
            $response->headers->set('Access-Control-Allow-Headers', implode(', ', CraftQL::getInstance()->getSettings()->allowedHeaders));
        }
        $response->headers->set('Allow', implode(', ', CraftQL::getInstance()->getSettings()->verbs));

I basically just set the header allow origin hardcoded to 'yolo'.

I get this when calling the API:

Access to fetch at 'https://cms.mypage.ch/api' from origin 'http://localhost:3000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: The 'Access-Control-Allow-Origin' header contains multiple values 'yolo, *', but only one is allowed. Have the server send the header with a valid value, or, if an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

-> Multiple values 'yolo, *',

Where could that additional asterix be added??

Jones-S commented 5 years ago

OK. My bad. Because I had some CORS issues once, I added allowed-origins within my htaccess. Those values there were added to the one that craftql was setting.

I removed my htaccess part and now it works.

Maybe craftql could check if there are some headers set somewhere? I just waisted hours and hours with this issue. Anyway, it is resolved. 🎉