49

I've looked for some ways to enable cors on laravel 5.1 specifically, I have found some libs like:

https://github.com/neomerx/cors-illuminate

https://github.com/barryvdh/laravel-cors

but none of them has a implementation tutorial specifically to Laravel 5.1, I tried to config but It doesn't work.

If someone already implemented CORS on laravel 5.1 I would be grateful for the help...

Matt
  • 14,906
  • 27
  • 99
  • 149
Leonardo Lobato
  • 1,047
  • 2
  • 9
  • 22
  • Barryvdh's is for Laravel 5, and really it should work out of the box with 5.1 as well. Did you try it? – rdiz Oct 12 '15 at 08:47
  • Yes I tried, but I still getting the following message ( it's a angular frontend) XMLHttpRequest cannot load http://api.address.com. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8080' is therefore not allowed access. But I have already added the local address on the cors files 'supportsCredentials' => true, 'allowedOrigins' => ['http://127.0.0.1:8080'], 'allowedHeaders' => ['*'], 'allowedMethods' => ['GET', 'POST', 'PUT', 'DELETE'], 'exposedHeaders' => [], 'maxAge' => 0, 'hosts' => [], – Leonardo Lobato Oct 12 '15 at 08:52
  • Which message do you get? – rdiz Oct 12 '15 at 08:53
  • XMLHttpRequest cannot load api.address.com. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin '127.0.0.1:8080'; is therefore not allowed access – Leonardo Lobato Oct 12 '15 at 08:55
  • Did you publish the config file and edit it accordingly? – rdiz Oct 12 '15 at 08:57
  • Did you have a look at the response header in your browser? There the Access-Control-Allow-Origin header should be set to the right domain. Also you could try to set it yourself on one route "by hand"... – Kjell Oct 12 '15 at 09:11
  • Access-Control-Allow-Credentials → true Access-Control-Allow-Headers → Origin, Content-Type, Accept, Authorization, X-Request-With Access-Control-Allow-Methods → GET, POST, OPTIONS Access-Control-Allow-Origin → * The cors seems to woking, I already tried my localhost instead of * but still don't working – Leonardo Lobato Oct 12 '15 at 09:48

9 Answers9

93

Here is my CORS middleware:

<?php namespace App\Http\Middleware;

use Closure;

class CORS {

    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {

        header("Access-Control-Allow-Origin: *");

        // ALLOW OPTIONS METHOD
        $headers = [
            'Access-Control-Allow-Methods'=> 'POST, GET, OPTIONS, PUT, DELETE',
            'Access-Control-Allow-Headers'=> 'Content-Type, X-Auth-Token, Origin'
        ];
        if($request->getMethod() == "OPTIONS") {
            // The client-side application can set only headers allowed in Access-Control-Allow-Headers
            return Response::make('OK', 200, $headers);
        }

        $response = $next($request);
        foreach($headers as $key => $value)
            $response->header($key, $value);
        return $response;
    }

}

To use CORS middleware you have to register it first in your app\Http\Kernel.php file like this:

protected $routeMiddleware = [
        //other middlewares
        'cors' => 'App\Http\Middleware\CORS',
    ];

Then you can use it in your routes

Route::get('example', array('middleware' => 'cors', 'uses' => 'ExampleController@dummy'));
Edit: In Laravel ^8.0 you have to import the namespace of the controller and use the class like this:
use App\Http\Controllers\ExampleController;

Route::get('example', [ExampleController::class, 'dummy'])->middleware('cors');
Alex Kyriakidis
  • 2,861
  • 1
  • 19
  • 28
  • Works on Apache but not IIS :( – suncoastkid Jan 11 '16 at 17:17
  • 4
    Just to clarify - is this an alternative to the packages mentioned in the question? – retrograde Apr 06 '16 at 18:58
  • 6
    @retrograde yeah if you pick this solution you don't have to use a package. – Alex Kyriakidis Apr 06 '16 at 19:01
  • 2
    This is really good solutions, also the OPTIONS method to check if Origin is allowed - like it in the middleware - But for some reason I can not get it all running for POST methods in laravel 5.X - Any ideas? – Ole K Sep 18 '16 at 13:28
  • Did you add a method spoof somewhere? When I call POST/GET I get to this middleware but using method OPTIONS I do not get to this middleware on the same route? Really odd... in the route list there is no OPTIONS method so I'm presuming it's possibly that the method OPTIONS is invalid OR being caught elsewhere. This is laravel 5.4 so could be something that's been added? – bashleigh May 01 '17 at 12:12
  • 10
    Note that, for me it is version 5.6 , and I also needed to add `\App\Http\Middleware\Cors::class` at Kernel.php, inside `protected $middleware` array. If anyone has suffer like me, can try this – arikanmstf Jul 20 '18 at 12:57
  • @AlexKyriakidis Thanks for the solution, as I am using the laravel5.7 and I have this syntax `return $next($request);` in my middleware. Should I use this or not? – shashi verma Nov 22 '18 at 04:32
  • This will enable access for the whole site / program, not just APIs. – Chamidu Jayaruwan Jun 01 '19 at 20:59
  • This is failing on OPTIONS. – darksoulsong Jul 22 '19 at 19:01
  • 1
    @arikanmstf you just made my week!! This was the problem I was having with my CORS. You are right, adding it to the protected $middleware in kernel.php fixed it! Many thanks. – Delmontee Sep 06 '19 at 06:39
  • Just add App\Http\Middleware\CORS::class in protected $middleware, and it will work for any request – Maxim Abdalov Nov 06 '19 at 10:41
  • THANK YOU! Jeez I've struggled with this for weeks. None of the packages worked for me. This is great! – user931018 Jan 22 '20 at 06:13
  • 1
    This didn't not work for me in Laravel 6.9, this did: https://github.com/fruitcake/laravel-cors – Cleanshooter Feb 05 '20 at 12:09
  • This is a nice and simple solution, much thanks. But I changed route on my web.php to get it working on Laravel 5.5 `Route::get('example', 'ExampleController@dummy')->middleware(CORS::class);` – mili Jun 24 '20 at 07:08
  • Worked like a charm for L5.2 for me.. just a quick note, CORS handling is inbuilt with L8 now.. Thanks – Prashant Mar 12 '21 at 07:37
  • This solution is generally too complex for those that want their local development environment to just work without the pain of CORS. – Bob Arezina May 19 '21 at 05:57
50

I always use an easy method. Just add below lines to \public\index.php file. You don't have to use a middleware I think.

header('Access-Control-Allow-Origin: *');  
header('Access-Control-Allow-Methods: GET, PUT, POST, DELETE, OPTIONS');
Joel James
  • 1,315
  • 1
  • 20
  • 37
13

I am using Laravel 5.4 and unfortunately although the accepted answer seems fine, for preflighted requests (like PUT and DELETE) which will be preceded by an OPTIONS request, specifying the middleware in the $routeMiddleware array (and using that in the routes definition file) will not work unless you define a route handler for OPTIONS as well. This is because without an OPTIONS route Laravel will internally respond to that method without the CORS headers.

So in short either define the middleware in the $middleware array which runs globally for all requests or if you're doing it in $middlewareGroups or $routeMiddleware then also define a route handler for OPTIONS. This can be done like this:

Route::match(['options', 'put'], '/route', function () {
    // This will work with the middleware shown in the accepted answer
})->middleware('cors');

I also wrote a middleware for the same purpose which looks similar but is larger in size as it tries to be more configurable and handles a bunch of conditions as well:

<?php

namespace App\Http\Middleware;

use Closure;

class Cors
{
    private static $allowedOriginsWhitelist = [
      'http://localhost:8000'
    ];

    // All the headers must be a string

    private static $allowedOrigin = '*';

    private static $allowedMethods = 'OPTIONS, GET, POST, PUT, PATCH, DELETE';

    private static $allowCredentials = 'true';

    private static $allowedHeaders = '';

    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
      if (! $this->isCorsRequest($request))
      {
        return $next($request);
      }

      static::$allowedOrigin = $this->resolveAllowedOrigin($request);

      static::$allowedHeaders = $this->resolveAllowedHeaders($request);

      $headers = [
        'Access-Control-Allow-Origin'       => static::$allowedOrigin,
        'Access-Control-Allow-Methods'      => static::$allowedMethods,
        'Access-Control-Allow-Headers'      => static::$allowedHeaders,
        'Access-Control-Allow-Credentials'  => static::$allowCredentials,
      ];

      // For preflighted requests
      if ($request->getMethod() === 'OPTIONS')
      {
        return response('', 200)->withHeaders($headers);
      }

      $response = $next($request)->withHeaders($headers);

      return $response;
    }

    /**
     * Incoming request is a CORS request if the Origin
     * header is set and Origin !== Host
     *
     * @param  \Illuminate\Http\Request  $request
     */
    private function isCorsRequest($request)
    {
      $requestHasOrigin = $request->headers->has('Origin');

      if ($requestHasOrigin)
      {
        $origin = $request->headers->get('Origin');

        $host = $request->getSchemeAndHttpHost();

        if ($origin !== $host)
        {
          return true;
        }
      }

      return false;
    }

    /**
     * Dynamic resolution of allowed origin since we can't
     * pass multiple domains to the header. The appropriate
     * domain is set in the Access-Control-Allow-Origin header
     * only if it is present in the whitelist.
     *
     * @param  \Illuminate\Http\Request  $request
     */
    private function resolveAllowedOrigin($request)
    {
      $allowedOrigin = static::$allowedOrigin;

      // If origin is in our $allowedOriginsWhitelist
      // then we send that in Access-Control-Allow-Origin

      $origin = $request->headers->get('Origin');

      if (in_array($origin, static::$allowedOriginsWhitelist))
      {
        $allowedOrigin = $origin;
      }

      return $allowedOrigin;
    }

    /**
     * Take the incoming client request headers
     * and return. Will be used to pass in Access-Control-Allow-Headers
     *
     * @param  \Illuminate\Http\Request  $request
     */
    private function resolveAllowedHeaders($request)
    {
      $allowedHeaders = $request->headers->get('Access-Control-Request-Headers');

      return $allowedHeaders;
    }
}

Also written a blog post on this.

Rishabh
  • 1,901
  • 2
  • 19
  • 18
  • Awesome, I read your blog post and it worked like a charm. Thanks! – darksoulsong Jul 22 '19 at 19:34
  • @Rishabh I Was just checking about some CORS related Laravel issues, almost every answer is just the same, but this one is actually very nice .. – Arun P Oct 11 '19 at 13:34
11

For me i put this codes in public\index.php file. and it worked just fine for all CRUD operations.

header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: GET, PUT, POST, DELETE, OPTIONS, post, get');
header("Access-Control-Max-Age", "3600");
header('Access-Control-Allow-Headers: Origin, Content-Type, X-Auth-Token');
header("Access-Control-Allow-Credentials", "true");

Sajad Haibat
  • 697
  • 5
  • 12
10

barryvdh/laravel-cors works perfectly with Laravel 5.1 with just a few key points in enabling it.

  1. After adding it as a composer dependency, make sure you have published the CORS config file and adjusted the CORS headers as you want them. Here is how mine look in app/config/cors.php

    <?php
    
    return [
    
        'supportsCredentials' => true,
        'allowedOrigins' => ['*'],
        'allowedHeaders' => ['*'],
        'allowedMethods' => ['GET', 'POST', 'PUT',  'DELETE'],
        'exposedHeaders' => ['DAV', 'content-length', 'Allow'],
        'maxAge' => 86400,
        'hosts' => [],
    ];
    
  2. After this, there is one more step that's not mentioned in the documentation, you have to add the CORS handler 'Barryvdh\Cors\HandleCors' in the App kernel. I prefer to use it in the global middleware stack. Like this

    /**
     * The application's global HTTP middleware stack.
     *
     * @var array
     */
    protected $middleware = [
        'Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode',
        'Illuminate\Cookie\Middleware\EncryptCookies',
        'Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse',
        'Illuminate\Session\Middleware\StartSession',
        'Illuminate\View\Middleware\ShareErrorsFromSession',
    
        'Barryvdh\Cors\HandleCors',
    
    ];
    

    But its up to you to use it as a route middleware and place on specific routes.

This should make the package work with L5.1

Emile Bergeron
  • 17,074
  • 5
  • 83
  • 129
Tariq Khan
  • 5,498
  • 4
  • 28
  • 34
  • I have been looking for details on each of the config file's elements especially 'exposedHeaders' and 'supportsCredentials', but unfortunately haven't had any success yet, do you mind to give some details on them or maybe post a reference please? much appreciated!! – Bahman.A Dec 17 '19 at 20:12
2

If you don't return a response from your route either through function closure or through controller action then it won't work.

It's not working

Controller Action

Route::post('login','AuthController@login');

class AuthController extends Controller {

     ...

     public function login() {
          dd(['key' => 'value']);
          //OR
          die(['key' => 'value']);
          //OR
          print_r(['key' => 'value');
          exit();
     }

     ...

}

It works!

Controller Action

Route::post('login','AuthController@login');

class AuthController extends Controller {

     ...

     public function login() {
          return response()->json(['key' => 'value'], 200);
          // OR
          return ['key' => 'value'];
          // OR
          $data = ['key' => 'value'];
          return $data;
     }

     ...

}

Test CORS

Chrome -> Developer Tools -> Network tab

enter image description here

If anything goes wrong then your response headers won't be here.

Indrasinh Bihola
  • 2,094
  • 3
  • 23
  • 25
2

Laravel 8

Create a middleware

<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;

class CorsMiddleware
{
    public function handle(Request $request, Closure $next)
    {
        return $next($request)
            ->header('Access-Control-Allow-Origin', config('cors.allowed_origins')) 
            ->header('Access-Control-Allow-Methods', config('cors.allowed_methods'))
            ->header('Access-Control-Allow-Headers',config('cors.allowed_headers'));
    }
}

config/cors.php

return [
    'paths' => [
        'api/*', 
        'admin/api/*', 
        'sanctum/csrf-cookie'
    ],
    'allowed_methods' => [ //'GET, POST, PUT, PATCH, DELETE, OPTIONS'
        'GET', 
        'POST', 
        'PUT', 
        'PATCH', 
        'DELETE', 
        'OPTIONS'
    ],
    'allowed_origins' => ['*'],
    'allowed_origins_patterns' => [],
    'allowed_headers' => [//  'Content-Type, Authorization, Accept'
        'Content-Type', 
        'Authorization', 
        'Accept'
    ],
    'exposed_headers' => [],
    'max_age' => 0,
    'supports_credentials' => true,
];

kernel.php for http

    protected $middleware = [
        ... ,
        \App\Http\Middleware\CorsMiddleware::class,  // Cors middlewate
    ];

Amir Daneshkar
  • 771
  • 3
  • 9
1

https://github.com/fruitcake/laravel-cors

Use this library. Follow the instruction mention in this repo.

Remember don't use dd() or die() in the CORS URL because this library will not work. Always use return with the CORS URL.

Thanks

0

just use this as a middleware

<?php

namespace App\Http\Middleware;

use Closure;

class CorsMiddleware
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        $response = $next($request);
        $response->header('Access-Control-Allow-Origin', '*');
        $response->header('Access-Control-Allow-Methods', '*');

        return $response;
    }
}

and register the middleware in your kernel file on this path app/Http/Kernel.php in which group that you prefer and everything will be fine

adnan ahmady
  • 770
  • 1
  • 7
  • 12