Has been blocked by CORS policy errors – Laravel Specific

Background

UPDATE 1 August 2020

This article was written when Laravel 6 was out and before first class CORS support was built into Laravel 7. Due to the integrated nature of CORS to an application we generally recommend you rather follow the official documentation when debugging Laravel issues with CORS. If you have’t upgraded to Laravel 7 yet, you are going to rapidly fall behind so we seriously recommend you do that. We have much success with Laravel Shift, but sometimes it a good learning exercise just to do it yourself.

Original Article

This article was compiled during a Laravel Development troubleshooting session and might not apply to other CORS sessions.

You might find yourself in a situation where you are trying to post from a REMOTE host to a LOCALHOST, especially during testing.

HTTPS should be set up properly. But instead of the post coming in, you get the following:

Access to XMLHttpRequest at 'https://sitename.test/api/v1/endpoint' from origin 'https://yourdomain.com' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.

This is a challenging problem to Google due to conflicting information on the internet. Here are a few options:

Option 1 (challenging)

Don’t do the Axois request through your browser. Do a server API and then use a CURL / Guzzlehttp request.

Option 2 (how to troubleshoot)

This error can come from many locations. Most notably you have to establish if you are having this problem because the server is blocking you, or if you can simply do something on the client to avoid it. If you don’t have control over the server then you will have limited options. So in this troubleshooting, try to determine if the server or the client is causing the problem.

If you are using Laravel, and you have server control, then the solution might be the Laravel CORS library by Barry vd Heuvel:

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

Here are brief instructions for installing this package

composer require barryvdh/laravel-cors

Then:

protected $middleware = [
    // ...
    \Barryvdh\Cors\HandleCors::class,
];

Then:

$ php artisan vendor:publish --provider="Barryvdh\Cors\ServiceProvider"

Make sure your Laravel app is setup with Passport. Here is a summary of most of the steps.:

composer require laravel/passport
php artisan migrate
php artisan passport:install

Add HasApiTokens to the user model:

class User extends Authenticatable
{
    use HasApiTokens, Notifiable;
}

In boot method of AuthServiceProvider add the Password::routes(); line as below:

class AuthServiceProvider extends ServiceProvider
{
    /**
     * The policy mappings for the application.
     *
     * @var array
     */
    protected $policies = [
        'App\Model' => 'App\Policies\ModelPolicy',
    ];

    /**
     * Register any authentication / authorization services.
     *
     * @return void
     */
    public function boot()
    {
        $this->registerPolicies();

        Passport::routes();
    }
}

Update the guards in config/auth.php the ‘api’  one make the driver ‘passport’.

'guards' => [
    'web' => [
        'driver' => 'session',
        'provider' => 'users',
    ],

    'api' => [
        'driver' => 'passport',
        'provider' => 'users',
    ],
],

If you’ve done all of the above, and you’re consuming your own API via your front-end, you’re in good stead because all you have to do now is:

https://laravel.com/docs/5.7/passport#consuming-your-api-with-javascript

'web' => [
    // Other middleware...
    \Laravel\Passport\Http\Middleware\CreateFreshApiToken::class,
],

Check the docs if it’s still not working 🙂

When not Consuming Own API

If you’re not consuming your own API and coming from another URL, e.g. a remote URL to your local testing URL.

You have to continue the Laravel guide, including getting those Vue components and tokens working.

php artisan vendor:publish tag=passportmigrations

php artisan vendor:publish --tag=passport-components

resources/js/app/js

Vue.component(
    'passport-clients',
    require('./components/passport/Clients.vue').default
);

Vue.component(
    'passport-authorized-clients',
    require('./components/passport/AuthorizedClients.vue').default
);

Vue.component(
    'passport-personal-access-tokens',
    require('./components/passport/PersonalAccessTokens.vue').default
);

npm run dev 

Then create a new page and add these components:

<passport-clients></passport-clients>
<passport-authorized-clients></passport-authorized-clients>
<passport-personal-access-tokens></passport-personal-access-tokens>

Then login, and create a user and a token. Below is a code sample but please note we have removed the very long bearer token and substituted it with very_long_bearer_token.

In your code:

axios.defaults.headers.common['Authorization'] = "Bearer " + 'very_long_bearer_token';

axios.post('https://project.test/api/v1/subscribe', {
   name: this.name,
   email: this.email
})
.then(function (response) {
   page.output = response.data;
})

.catch(function (error) {
   page.output = error;
});

}

If you’ve made it this far, congratulations! You’ve just digested a lot of information and I hope this will assist you in fixing the CORS issue. Please leave a comment or get in touch if you need additional help.

Share this article

Leave a Reply

Your email address will not be published. Required fields are marked *

Scroll to Top