← Blog

The Curse of CORS

Marco Montorsi

How CORS works, explanation of implementation phases, and how it's managed in the HTTP flow and in Laravel.

The Curse

Anyone who professes to be a web developer in the course of their professional life must have encountered this error at least once:

Access to XMLHttpRequest at 'https://api.marcomontorsi.it/data' from origin 'https://www.marcomontorsi.it'
has been blocked by CORS policy:
No 'Access-Control-Allow-Origin' header is present on the requested resource.

The origin of the error stems from the meaning of the CORS acronym, which stands for: Cross-Origin Resource Sharing.

As a security system against attacks such as CSRF (Cross-Site Request Forgery), by default, requests from domains different from that of the application are blocked.

This system was convenient in the early days of web applications when applications were often monolithic. But nowadays, it's common to have at least the frontend logic separated from the backend or to make calls to third-party REST or SOAP APIs.

So, the need for requests to domains different from the application has grown significantly. To address this need, the CORS policy was introduced. By using appropriate headers in the response, calls from other domains are authorized. To better understand how CORS works, one must understand the division between the preflight and main request.

Preflight Request

This request is managed by the browser and is executed before the main request, using an HTTP request with the OPTIONS method. It verifies whether it's authorized to proceed with the request from a different domain.

As verification parameters, the following headers are sent along with the request:

  • Access-Control-Request-Method: HTTP method to be used in the main request (e.g., POST).
  • Access-Control-Request-Headers: list of headers to be used in the main request.

If the server responds positively, it includes the following headers:

  • Access-Control-Allow-Methods: List of permitted HTTP methods.
  • Access-Control-Allow-Headers: List of permitted headers.
  • Access-Control-Max-Age: Number of seconds the browser can cache the response to avoid sending preflight requests continuously.

Main Request

In case of a positive preflight request, the "main" request is sent to the server, specifying in a header the origin of the call (e.g., origin: marcomontorsi.it).

The server's response is subsequently completed with an Access-Control-Allow-Origin header, which indicates the allowed origin for the API. The value can be chosen from:

  • null: Unauthorized origin.
  • '*': Any allowed origin.
  • A single origin like https://example.com.

Flowchart

Flowchart

CORS in Laravel

In Laravel, CORS management is entrusted to the file in config/cors.php:

<?php

return [

    'paths' => ['api/*', 'sanctum/csrf-cookie'], // Specific paths within the application to which CORS rules defined in the configuration will be applied.

    'allowed_methods' => ['*'], // Allowed methods, with the asterisk, any method is allowed.

    'allowed_origins' => ['*'], // Enabled domains, with the asterisk, any domain is allowed.

    'allowed_origins_patterns' => [], // This key allows specifying a list of regular patterns (regex) that define the allowed origins for CORS requests.

    'allowed_headers' => ['*'], // Allowed headers, with the asterisk, any header is allowed.

    'exposed_headers' => [], // This key allows specifying a list of custom headers that can be exposed to the client as part of the response. These custom headers can be accessible via JavaScript on the client if specified here.

    'max_age' => 0, // Number of seconds the browser can cache the response to avoid sending preflight requests continuously.

    'supports_credentials' => false, // Whether the server will allow the passing of credentials in CORS requests or not.
    // https://stackoverflow.com/questions/69481452/what-does-supports-credential-mean-in-the-laravel-cors-php-file
];
← All articles