Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

mmichaelbiz's avatar

OK, have tried the solutions proposed in this thread plus a bunch of others but still no joy.

Similar scenario to many here, in that the OPTIONS request comes back without any of the headers set in the middleware.

Using latest stable Laravel 5 as my API back end. Trying to consume it with an AngularJS front end.

Both dev sites running on homestead at the moment so all through nginx.

As a side note I couldn't for the life of me get the CSRF to behave so got rid of it completely and have replaced it with JWT which is working great so far.

Have been able to test using the Chrome extension "Allow-Control-Allow-Origin: * " which I picked up the hint from here: http://stackoverflow.com/questions/21102690/angularjs-not-detecting-access-control-allow-origin-header (seems Taylor ran in to similar grief over a year ago)

Now if only I could get the requests across to Laravel without this extension that would be awesome!

@JeffreyWay can you come and save the day?

mmichaelbiz's avatar

No. Not using any package for CORS.

Pure Laravel plus a middleware file called on the route group housing the api routes.

Which one is yours?

I do try to keep the number of additional packages to a minimal however especially in matters of auth and security.

mmichaelbiz's avatar

Just noticed that the above post from patton517 (and their other posts) seem to be spam, containing links to some shoddy software site disguised as the username links.

Adding @JeffreyWay if you want to remove them. Might be time for a 'report this post' function on this awesomely constructed forum :)

gio1994's avatar

Laravel 5.1 CORS FIX

in terminal --> php artisan make:middleware CORS

That File will be located in /app/Http/Middleware/CORS.php

Open It. Lol

Paste this into the handle function (It should be the only function in there)

$http_origin = isset($_SERVER['HTTP_ORIGIN']) ? $_SERVER['HTTP_ORIGIN'] : false; $allowed_origins = ['http://sub.example.com' , 'http://example.com'];

    if(in_array($http_origin, $allowed_origins)) {
        return $next($request)->header('Access-Control-Allow-Origin' , '*')
          ->header('Access-Control-Allow-Methods', 'POST, GET, OPTIONS, PUT, DELETE')
          ->header('Access-Control-Allow-Headers', 'Content-Type, Accept, Authorization, X-Requested-With');
    }
    
    return $next($request);

After that Your going to want to go and Edit you Kernel.php File

add -> \App\Http\Middleware\CORS::class to the array of $middleware

**** On another note, If you wanted to disable verifyCsrToken you would just comment out \App\Http\Middleware\VerifyCsrfToken::class, and your good to go!

I hope this works for you.

civaqhar's avatar

Try this.

public function handle($request, Closure $next)
{
    $headers = [
        'Access-Control-Allow-Origin' => '*',
        'Access-Control-Allow-Methods'=> 'POST, GET, OPTIONS, PUT, DELETE',
        'Access-Control-Allow-Headers'=> 'Content-Type, X-Auth-Token, Origin, Authorization'
    ];

    if($request->getMethod() == "OPTIONS") {

        $response = new Response();
        foreach($headers as $key => $value)
            $response->headers->set($key, $value);

        return $response;
    }

    $response = $next($request);

    foreach($headers as $key => $value)
        $response->headers->set($key, $value);

    return $response;
}
3 likes
cbil360's avatar

I am working on implementing the same. I do not get the CORS error anymore,but my sessions are not working! My Auth::check() method always returns false. Is laravel doing this just because the domain is different?

I am testing this on my local machine using grunt, my app loads after grunt serve.When I hit my login route,the user is authenticated against the database and ideally should go to /dashboard,but as the session is not set or probably unset due to URL (not sure), I again come back to login page.

My app url is localhost:9000 which is called after I run grunt serve. My angular app is inside a folder angular at the root of my application directory (same level as laravel public folder). @Barryvdh

hootlex's avatar

The problem is that OPTIONS method is not triggering the expected middleware. After a lot of digging I ended up to enable CORS middleware globaly and applying it to specific segments (ex: /api/*) Here is my GLOBAL CORS middleware for anyone who needs it in the futute

<?php namespace App\Http\Middleware;

use Closure;
use Request;
use Response;

class CORS {

    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        //apply cors only to api routes
        if(Request::segment(1)=='api') {
            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, Authorization'
            ];
            if($request->isMethod("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);
            }
        }else{
            $response = $next($request);
        }
        return $response;
    }

}
enginebit's avatar

Laravel already answers to the OPTIONS method if no route is found for the uri!

https://github.com/laravel/framework/blob/5.1/src/Illuminate/Routing/RouteCollection.php#L152-L159

So Basically what you just need is the following

<?php namespace App\Http\Middleware;

use Closure;
use Request;

class CORS {

    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        /*
         * Get the response like normal.
         * When laravel cannot find the exact route it will try to find the same route for different methods
         * If the method is OPTION and there are other methods for the uri,
         * it will then return a 200 response with an Allow header
         *
         * Else it will throw an exception in which case the user is trying to do something it should not do.
         */
        $response = $next($request);

        // We only want the headers set for the api requests
        if ($request->segment(1) == 'api') {

            // Set the default headers for cors If you only want this for OPTION method put this in the if below
            $response->headers->set('Access-Control-Allow-Origin','*');
            $response->headers->set('Access-Control-Allow-Headers','Content-Type, X-Auth-Token, Origin, Authorization');

            // Set the allowed methods for the specific uri if the request method is OPTION
            if ($request->isMethod('options')) {
                
                $response->headers->set(
                    'Access-Control-Allow-Methods',
                    $response->headers->get('Allow')
                );
            }

        }

        return $response;
    }
}
1 like
timhaak's avatar

Is there a reason why people aren't using the https://github.com/barryvdh/laravel-cors ?

More asking as though I know it's not that complicated to implement yourself.

Nice to have a community maintained version that can get shared fixes.

1 like
bipinu's avatar

I am facing the same issue with none of the headers being returned for Pre-flight request. However, this happens on an Ubuntu box. The same piece of code works flawlessly on OS X 10.11 Does anyone have any fresh insights on this?

@timhaak Packages are awesome for complex things. I use @Barryvdh's debugbar package and love it. However, you try not to rely on packages for everything.

bipinu's avatar

Alrighty! I think I have figured it out. At least for L5.1

As per https://github.com/laravel/framework/blob/5.1/src/Illuminate/Routing/RouteCollection.php#L152-L161, if we do not have a route that handles the OPTIONS call, Laravel decides to respond itself. Details in the source code.

Thankfully, Laravel also supports handling of OPTIONS calls. So this should fix things for you. (Note: You still need your middleware to send appropriate headers)

Route::option('{all}', function(){
    return response('',204);
})->where('all', '.*');

In case you cache your routes file, use something like this:

Route::options('{all}', [
    'uses'  => 'SuperCoolMedler@handleOptionsCalls',
    'as'    => 'handle.options.calls'
])->where('all', '.*');
ayekoto's avatar

Well am still battling with same problem when i come across this trend, and I would rather not use that barryvdh cors package cos I have tried it earlier but not working... Lemme try the above examples first to know if I did get a solution

suncoastkid's avatar

@Barryvdh Thank you very much! You've saved the day yet again. I've been banging my head against the wall on a CORS issue using L5 and Vue.js until I found your package. Your contributions to the community are really appreciated.

rmff's avatar

Just remember, you need to have a route for 'OPTIONS' on Routes file.

Route::match(['post', 'options'], 'api/foo', 'Api\FooController@bar')->middleware('cors');

On CORS Middleware you can use some test for 'OPTIONS'. Using this you don't need an method for 'OPTIONS' on controller

    public function handle($request, Closure $next)
    {

        $headers = [
            'Access-Control-Allow-Origin'      => $_SERVER['HTTP_ORIGIN'],
            // CORS doesn't accept Access-Control-Allow-Origin = * for security reasons
            //'Access-Control-Allow-Origin'    => '*',
            'Access-Control-Allow-Methods'     => 'POST, OPTIONS',
            //'Access-Control-Allow-Methods'   => 'POST, GET, OPTIONS, PUT, DELETE',
            'Access-Control-Allow-Credentials' => 'true',
            'Access-Control-Max-Age'           => '86400',
            'Access-Control-Allow-Headers'     => 'Content-Type, Authorization, X-Requested-With',
            //'Access-Control-Allow-Headers'   => 'X-Custom-Header, X-Requested-With, Content-Type, Origin, Authorization, Accept, Client-security-token',
        ];


        //Using this you don't need an method for 'OPTIONS' on controller
        if($request->isMethod('OPTIONS'))
            return Response::json('{"method":"OPTIONS"}', 200, $headers);

        // For all other cases
        $response = $next($request);
        foreach($headers as $key => $value)
            $response->header($key, $value);

        return $response;
}

My code was based on various codes and solutions founded here and in WEB

meduz's avatar

Update : I just noticed my form action attribute was absolute URL instead of relative. I'm gonna show myself the way out, thanks for your attention. By the way, maybe is my question about wilcard safety still relevant.

Hi!

I read the whole thread. Some question regarding the subject of CORS /w local development. My back-end experience is limited, I'm a front-end guy.

When working locally with a proxy (e.g. BrowserSync allowing you to access yourwebsite.dev through _localhost:3000_), my current solution looks a bit filthy: in the Laravel .env file, I added a APP_URL_CORS const set to * for the local development .env file, and set to yourwebsite.dev for other cases (production, staging, whatever…).

Then, I add this to every AJAX request:

return response()
    ->json($things_for_the_browser)
    ->header('Access-Control-Allow-Origin', env('APP_URL_CORS'));

This works, but looks a bit crappy to me.

I understand your solution, but isn’t it a bit unsafe to allow every origins with the wildcard? Or did I miss something?

Thanks!

meduz's avatar

Update: I'll update my post in a few seconds. Seems like my brain has freeze a bit today. ~~

jcarmonamx's avatar

Hi, this working for me (Laravel 5.2)

<?php

namespace App\Http\Middleware;

use Closure;

use Illuminate\Http\Response;

class CORSMiddleware
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        if (isset($_SERVER['HTTP_ORIGIN'])) {

            $permit = false;

            switch ($_SERVER['HTTP_ORIGIN']) {
                case 'some url':
                    $permit = true;
                break;
                case 'some url':
                    $permit = true;
                break;
            }

            if ($permit == true) {
                return $next($request)
                    ->header('Access-Control-Allow-Origin', $_SERVER['HTTP_ORIGIN'])
                    ->header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
            } else {
                return $next($request);
            }

        } else {
            return $next($request);
        }
    }
}

rishabhp's avatar

I needed to do this recently and this is how my middleware looks:

<?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;
    }
}

Of course don't forget to add it to your app/Http/Kernel.php like this:

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

Even written an article on this explaining the different parts of the code as well as different approaches.

1 like
orrd's avatar

I used a technique similar to rishabhp's post and that worked great (and yes, https://github.com/barryvdh/laravel-cors is also an option for anyone who prefers to use a package to do it).

One big catch to be aware of... if you're using Route::any(), it won't work because Laravel didn't include the 'OPTIONS' method as one of the "any" routes it accepts. You have to explicitly specify Route::options() in your routes file, or use Route::match()with the 'OPTIONS' method listed.

Previous

Please or to participate in this conversation.