Ad

No Cors Headers Added To Response

- 1 answer

When trying to log in using an API (hosted locally) from a React application, I get this error every time:
Error image

I know there area lot of topics on this subject, but none of them helped me. Perhaps because I missed something, or don't understand the concept.

I have no idea anymore how to fix this.

Things I already tried:
- Added a HTTP middleware (code will follow): didn't work.
- Tried fixing it with the spatie/laravel-cors package: didn't work.
- Tried fixing it with the barryvdh/laravel-cors: didn't work either.

I am out of ideas. Does someone know what I am doing wrong?

My code

protected $middleware = [
    \App\Http\Middleware\CheckForMaintenanceMode::class,
    \Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
    \App\Http\Middleware\TrimStrings::class,
    \Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
    \App\Http\Middleware\TrustProxies::class,
    \Spatie\Cors\Cors::class, // <-- this line would be pointed to my own middleware when that would be in use
];

The following code is pointed to instead of \Spatie\Cors\Cors::class, if I where to use my own middleware

class ApiCors
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        return $next($request)
            ->header('Access-Control-Allow-Origin', '*')
            ->header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS, PATCH')
            ->header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept, Authorization');

    }
}
Ad

Answer

There are some tricky things with implementing CORS support:

  1. Your CORS middleware should be added to global middleware stack, because browser could send Preflight request, and you wouldn't want to have specific OPTIONS route for every API route.

  2. Middleware doesn't need to pass Preflight request deeper to application.

  3. CORS header(s) should be added both to Preflight requests and API request.

So, that's how it should be done:

Create middleware:

php artisan make:middleware ApiCors

Put the code:

<?php

namespace App\Http\Middleware;

use Closure;

class ApiCors {

  /**
   * Handle an incoming request.
   *
   * @param  \Illuminate\Http\Request $request
   * @param  \Closure $next
   *
   * @return mixed
   */
  public function handle($request, Closure $next)
  {
    $isPreflight = $request->isMethod('options') && $request->hasHeader('origin');

    // we don't need to process Preflight request further
    $response = $isPreflight ? response()->make() : $next($request);

    if($isPreflight) {
      $response
        ->header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS, PATCH')
        ->header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept, Authorization')
        ->header('Access-Control-Max-Age', 86400);
    }
    $response->header('Access-Control-Allow-Origin', $isPreflight ? '*' : ($request->header('origin') ?? '*'));

    return $response;
  }
}

Register middleware:

app/Http/Kernel.php:

<?php
// ...
use App\Http\Middleware\ApiCors;

class Kernel extends HttpKernel {
  // ...
  protected $middleware = [
    // ...
    ApiCors::class,
  ];
  // ...
  protected $middlewarePriority = [
    ApiCors::class, // move to the top of the chain
    // ...
  ];
}

Test middleware:

Let's add simple API route.

routes/api.php:

Route::put('/v1/test', function () {
  return response()->json(['answer' => 42]);
});

Let's start simple server (run in Laravel project root folder):

php -S localhost:8088 -t public

Next, open any webpage (or use current one) and run in developer console:

fetch('http://localhost:8088/api/v1/test', {
  method: 'PUT', headers: { 'accept': 'application/json' }
}).then(r => r.json()).then(console.log.bind(console))

You should get response:

{answer: 42}

Don't forget that you should add your [external] API routes to routes/api.php, not to the routes/web.php, because web routers group has numerous middlewares which could interfere with your api ones, such as VerifyCsrfToken, for example.

MDN: Cross-Origin Resource Sharing (CORS)

Ad
source: stackoverflow.com
Ad