CORS (Cross Origin Resource Sharing) in drupal 8

drupal 8 cors fix

I was developing an Ionic Hybrid App that fetches results from the Drupal 8 website and shows recent news with categories. That app also has some basic features like login, signup, bookmarking articles and commenting.

Drupal 8 have built-in modules for REST Web Services which expose entities and other resource using REST API endpoints. I also build some custom REST resources to send a response in my way, And in App, I have implemented some providers which send ajax request to endpoints with HTTP Basic Authentication and get JSON response for App. It’s a simple approach but during the development phase, I got CORS error when App ajax hit the to REST endpoint. After some research, I have found some solution which works for me.

How to set CORS headers in drupal 8?

You can set CORS header in either way listed below.

1:- Setting CORS in services.yml

cors.config:
    enabled: true
    # Specify allowed headers, like 'x-allowed-header'.
    allowedHeaders: ['x-csrf-token','authorization','content-type','accept','origin','x-requested-with', 'access-control-allow-origin','x-allowed-header']
    # Specify allowed request methods, specify ['*'] to allow all possible ones.
    allowedMethods: ['POST', 'GET', 'OPTIONS', 'PATCH', 'DELETE']
    # Configure requests allowed from specific origins.
    allowedOrigins: ['*']
    # Sets the Access-Control-Expose-Headers header.
    exposedHeaders: true
    # Sets the Access-Control-Max-Age header.
    maxAge: false
    # Sets the Access-Control-Allow-Credentials header.
    supportsCredentials: true

Make sure you put only those header which you required ( Avoid extra ) or enable only that configuration that you required for security purpose.

2:- Send header from your custom REST plugin resource with the response.

<?php
/**
* function can be get, post, patch, delete 
**/
function post($lang) {
   // Resource response
   $headers = [
      'Access-Control-Allow-Origin' => '*',
      'Access-Control-Allow-Methods' => 'POST, GET, OPTIONS, PATCH, DELETE',
      'Access-Control-Allow-Headers' => 'Authorization'
    ];
    $response = new ResourceResponse($response_result, $response_code, $headers);
    // Configure caching for results
    if ($response instanceof CacheableResponseInterface) {
        $response->addCacheableDependency(new ArticleCachableDepenency(count($response_result),$entities));
    }
    return $response;
}

This function is extracted from my custom rest resource plugin.

3:- Using Event Subscriber.

Register event subscriber service in module's service file.

services:
  cross_origin_request:
    class: Drupal\custom_api\EventSubscriber\CrossOriginRequestEventSubscriber
    tags:
      - {name: event_subscriber}

And CrossOriginRequestEventSubscriber class is below

<?php

namespace Drupal\custom_api\EventSubscriber;

use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\HttpKernel\Event\FilterResponseEvent;


class CrossOriginRequestEventSubscriber implements EventSubscriberInterface {

  public function setCrossOriginHeader(FilterResponseEvent $event) {
    // This will run for all the response
    // You might need to add a check here to identify api calls
    $response = $event->getResponse();
    $response->headers->set('Access-Control-Allow-Origin', '*');
    $response->headers->set('Access-Control-Allow-Methods', 'POST, GET, OPTIONS, PATCH, DELETE');
    $response->headers->set('Access-Control-Allow-Headers', 'Authorization,Content-Type,X-CSRF-Token');
  }

  /**
   * {@inheritdoc}
   */
  static public function getSubscribedEvents() {
    $events[KernelEvents::RESPONSE][] = ['setCrossOriginHeader', -10];
    return $events;
  }

}