getcandy / hub

GetCandy v1 Hub built on Nuxt.js
30 stars 9 forks source link

Credential is not supported if the CORS header ‘Access-Control-Allow-Origin’ is ‘*’ #11

Closed taiwanleaftea closed 3 years ago

taiwanleaftea commented 4 years ago

Getcandy API installed local at http://getcandy.local Getcandy HUB installed on the same computer at http://localhost:3000

I can access the API via curl from the terminal.

When I open http://localhost:3000, I see the login form, but can't login because of the CORS error:

Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at ‘http://getcandy.local/api/v1/users/current?includes=roles.permissions,details’. (Reason: Credential is not supported if the CORS header ‘Access-Control-Allow-Origin’ is ‘*’).

I tried Firefox 77.0.1 and Safari 13.1.1

alecritson commented 4 years ago

Which method are you using to authenticate? Are you using Sanctum?

taiwanleaftea commented 4 years ago

Yes, Sanctum. In Sanctums' cors config

'supports_credentials' => true,

headers received from nginx seems to be ok

HTTP/1.1 204 No Content Server: nginx/1.10.3 Date: Thu, 18 Jun 2020 10:22:48 GMT Connection: keep-alive Access-Control-Allow-Origin: http://localhost:3000 Access-Control-Allow-Credentials: true Access-Control-Allow-Methods: GET, POST, OPTIONS Access-Control-Allow-Headers: DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type Access-Control-Max-Age: 1728000 Content-Type: text/plain charset=UTF-8 Content-Length: 0

there are request headers:

Host: getcandy.local User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:77.0) Gecko/20100101 Firefox/77.0 Accept: / Accept-Language: ru,ru-RU;q=0.8,en;q=0.5,en-US;q=0.3 Accept-Encoding: gzip, deflate Access-Control-Request-Method: GET Access-Control-Request-Headers: x-candy-hub,x-requested-with Referer: http://localhost:3000/login Origin: http://localhost:3000 DNT: 1 Connection: keep-alive Cache-Control: max-age=0

alecritson commented 4 years ago

Have you added localhost:3000 to SANCTUM_STATEFUL_DOMAINS and also if you're using localhost, make sure you set SESSION_DOMAIN to an empty string.

taiwanleaftea commented 4 years ago

config/sanctum.php

'stateful' => explode(',', env('SANCTUM_STATEFUL_DOMAINS', 'localhost:3000,localhost,127.0.0.1,127.0.0.1:8000,::1')),

config/session.php

'domain' => env('SESSION_DOMAIN', null),

The variables are not set in the .env

In the Sanctums' documentation is written:

In addition, you should enable the withCredentials option on your global axios instance. Typically, this should be performed in your resources/js/bootstrap.js file: axios.defaults.withCredentials = true;

but I don't understand where this config is located.

alecritson commented 4 years ago

Set SESSION_DOMAIN to "" in your .env file and see if that helps. Also make sure your SESSION_DRIVER is set to cookie

taiwanleaftea commented 4 years ago

Both not work. This one:

SESSION_DRIVER=cookie SESSION_LIFETIME=120 SESSION_DOMAIN=""

and this:

SESSION_DRIVER=cookie SESSION_LIFETIME=120 SESSION_DOMAIN=

Maybe is something wrong with X-CANDY-HUB request header, because Safari shows me this message in the console

Request header field X-CANDY-HUB is not allowed by Access-Control-Allow-Headers.

Repox commented 4 years ago

Could you perhaps take a look at this video I made? Just to ensure that you didn't skip any important steps. Remember to read the videos description too.

It's a realtime paced installation process that shows how to set up the API and Admin Hub.

If you still cannot make it work, could you maybe share the contents, preferably in a (private) Gist or similar, of the following files in the API:

And finally, the .env you've created for the Admin Hub.

taiwanleaftea commented 4 years ago

Just to ensure that you didn't skip any important steps

I use virtualbox instead of docker, and I found the difference. I copied from the docs (in hub .env and api.php) "login", but according to your video it must be "v1/login". Now I don't get the CORS error, but get another:

The GET method is not supported for this route. Supported methods: POST.

But I don't see any GET request in the network inspector (see screenshot).

screen

I've attached files. This is a fresh Laravel installation for testing, so the files don't contain any confidential information.

env-api.txt cors.php.txt RouteServiceProvider.php.txt api.php.txt env-hub.txt

taiwanleaftea commented 4 years ago

Here is the response from the API

{ "message": "The GET method is not supported for this route. Supported methods: POST.", "exception": "Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException", "file": "/media/sf_www/getcandy/vendor/laravel/framework/src/Illuminate/Routing/AbstractRouteCollection.php", "line": 117, "trace": [ { "file": "/media/sf_www/getcandy/vendor/laravel/framework/src/Illuminate/Routing/AbstractRouteCollection.php", "line": 103, "function": "methodNotAllowed", "class": "Illuminate\Routing\AbstractRouteCollection", "type": "->" }, { "file": "/media/sf_www/getcandy/vendor/laravel/framework/src/Illuminate/Routing/AbstractRouteCollection.php", "line": 40, "function": "getRouteForMethods", "class": "Illuminate\Routing\AbstractRouteCollection", "type": "->" }, { "file": "/media/sf_www/getcandy/vendor/laravel/framework/src/Illuminate/Routing/RouteCollection.php", "line": 162, "function": "handleMatchedRoute", "class": "Illuminate\Routing\AbstractRouteCollection", "type": "->" }, { "file": "/media/sf_www/getcandy/vendor/laravel/framework/src/Illuminate/Routing/Router.php", "line": 639, "function": "match", "class": "Illuminate\Routing\RouteCollection", "type": "->" }, { "file": "/media/sf_www/getcandy/vendor/laravel/framework/src/Illuminate/Routing/Router.php", "line": 628, "function": "findRoute", "class": "Illuminate\Routing\Router", "type": "->" }, { "file": "/media/sf_www/getcandy/vendor/laravel/framework/src/Illuminate/Routing/Router.php", "line": 617, "function": "dispatchToRoute", "class": "Illuminate\Routing\Router", "type": "->" }, { "file": "/media/sf_www/getcandy/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php", "line": 165, "function": "dispatch", "class": "Illuminate\Routing\Router", "type": "->" }, { "file": "/media/sf_www/getcandy/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php", "line": 128, "function": "Illuminate\Foundation\Http\{closure}", "class": "Illuminate\Foundation\Http\Kernel", "type": "->" }, { "file": "/media/sf_www/getcandy/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/TransformsRequest.php", "line": 21, "function": "Illuminate\Pipeline\{closure}", "class": "Illuminate\Pipeline\Pipeline", "type": "->" }, { "file": "/media/sf_www/getcandy/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php", "line": 167, "function": "handle", "class": "Illuminate\Foundation\Http\Middleware\TransformsRequest", "type": "->" }, { "file": "/media/sf_www/getcandy/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/TransformsRequest.php", "line": 21, "function": "Illuminate\Pipeline\{closure}", "class": "Illuminate\Pipeline\Pipeline", "type": "->" }, { "file": "/media/sf_www/getcandy/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php", "line": 167, "function": "handle", "class": "Illuminate\Foundation\Http\Middleware\TransformsRequest", "type": "->" }, { "file": "/media/sf_www/getcandy/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/ValidatePostSize.php", "line": 27, "function": "Illuminate\Pipeline\{closure}", "class": "Illuminate\Pipeline\Pipeline", "type": "->" }, { "file": "/media/sf_www/getcandy/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php", "line": 167, "function": "handle", "class": "Illuminate\Foundation\Http\Middleware\ValidatePostSize", "type": "->" }, { "file": "/media/sf_www/getcandy/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/CheckForMaintenanceMode.php", "line": 63, "function": "Illuminate\Pipeline\{closure}", "class": "Illuminate\Pipeline\Pipeline", "type": "->" }, { "file": "/media/sf_www/getcandy/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php", "line": 167, "function": "handle", "class": "Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode", "type": "->" }, { "file": "/media/sf_www/getcandy/vendor/fruitcake/laravel-cors/src/HandleCors.php", "line": 57, "function": "Illuminate\Pipeline\{closure}", "class": "Illuminate\Pipeline\Pipeline", "type": "->" }, { "file": "/media/sf_www/getcandy/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php", "line": 167, "function": "handle", "class": "Fruitcake\Cors\HandleCors", "type": "->" }, { "file": "/media/sf_www/getcandy/vendor/fideloper/proxy/src/TrustProxies.php", "line": 57, "function": "Illuminate\Pipeline\{closure}", "class": "Illuminate\Pipeline\Pipeline", "type": "->" }, { "file": "/media/sf_www/getcandy/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php", "line": 167, "function": "handle", "class": "Fideloper\Proxy\TrustProxies", "type": "->" }, { "file": "/media/sf_www/getcandy/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php", "line": 103, "function": "Illuminate\Pipeline\{closure}", "class": "Illuminate\Pipeline\Pipeline", "type": "->" }, { "file": "/media/sf_www/getcandy/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php", "line": 140, "function": "then", "class": "Illuminate\Pipeline\Pipeline", "type": "->" }, { "file": "/media/sf_www/getcandy/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php", "line": 109, "function": "sendRequestThroughRouter", "class": "Illuminate\Foundation\Http\Kernel", "type": "->" }, { "file": "/media/sf_www/getcandy/public/index.php", "line": 55, "function": "handle", "class": "Illuminate\Foundation\Http\Kernel", "type": "->" } ] }

Repox commented 4 years ago

This might seem trivial, but could you possibly try and move the registered routes in the RouteServiceProvider.php above the $this->mapApiRoutes(); and $this->mapWebRoutes(); instead of the placing now?

And additionally, can you also share the config/sanctum.php file?

taiwanleaftea commented 4 years ago

move the registered routes in the RouteServiceProvider.php above the $this->mapApiRoutes(); and $this->mapWebRoutes();

screen

The same error.

sanctum.php.txt

Repox commented 4 years ago

Looks good. I see an error on the sweet-jar.jpg. Could you try and open the hub in an incognito window?

And you don't have Auth::routes() in your routes/web.php?

taiwanleaftea commented 4 years ago

I see an error on the sweet-jar.jpg. Could you try and open the hub in an incognito window?

The same error. As I can see, the sweet-jar.jpg is loaded twice: the first call to http://localhost:3000/sweet-jar.jpg returns 404 error, the second to http://localhost:3000/_nuxt/assets/images/sweet-jar.jpg returns the image.

And you don't have Auth::routes() in your routes/web.php?

I have default closure from Laravel, and nothing more:

Route::get('/', function () { return view('welcome'); });

Maybe it would be helpful, here is the output from php artisan route:list

routes.txt

Repox commented 4 years ago

It seems weird. There are no GET requests. Maybe it's related to your VirtualBox setup. Can you share details about it? Have you tried my Docker approach?

taiwanleaftea commented 4 years ago

Virtualbox 6.1 with virtual host adapter. getcandy.local mapped to the IP of this adapter in /etc/hosts

In Virtualbox I have debian 9 with nginx, mariadb, elasticsearch, and php-fpm 7.4. Laravel 7.16.1.

In nginx config for Getcandy I've added following:

 if ($request_method = 'OPTIONS') {
    add_header 'Access-Control-Allow-Origin' $http_origin;

    #
    # Om nom nom cookies
    #

    add_header 'Access-Control-Allow-Credentials' 'true';
    add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';

    #
    # Custom headers and headers various browsers *should* be OK with but aren't
    #

    add_header 'Access-Control-Allow-Headers' 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,X-Candy-Hub,If-Modified-Since,Cache-Control,Content-Type';

    #
    # Tell client that this pre-flight info is valid for 20 days
    #

    add_header 'Access-Control-Max-Age' 1728000;
    add_header 'Content-Type' 'text/plain charset=UTF-8';
    add_header 'Content-Length' 0;

    return 204;
 }

 if ($request_method = 'POST') {

    add_header 'Access-Control-Allow-Origin' $http_origin;
    add_header 'Access-Control-Allow-Credentials' 'true';
    add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
    add_header 'Access-Control-Allow-Headers' 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,X-Candy-Hub,If-Modified-Since,Cache-Control,Content-Type';
 }

 if ($request_method = 'GET') {

    add_header 'Access-Control-Allow-Origin' $http_origin;
    add_header 'Access-Control-Allow-Credentials' 'true';
    add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
    add_header 'Access-Control-Allow-Headers' 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,X-Candy-Hub,If-Modified-Since,Cache-Control,Content-Type';
 } 

If remove it, and get CSRF token mismatch. error.

CORS nginx config is discussed here https://gist.github.com/michiel/1064640

Have you tried my Docker approach?

I can try. Where can I find it?

Repox commented 4 years ago

If remove it, and get CSRF token mismatch. error.

Well, that at least states that you actually reach the Laravel instance and your requests aren't rewritten. I do believe that it's your Nginx configuration that is messing everything up.

You can try the configuration that I'm using in the Docker-setup instead: https://github.com/Repox/getcandy-docker/blob/master/docker/nginx/docker-vhost.conf

That configuration allows you to manage the CORS via the CORS package included in Laravel.

My complete Docker setup can be found here.

taiwanleaftea commented 4 years ago

You can try the configuration that I'm using in the Docker-setup instead:

I tried your nginx config, and got CSRF token mismatch.

I can see two requests:

  1. GET http://getcandy.local/api/v1/sanctum/csrf-cookie has 3 cookies
scr1
  1. POST http://getcandy.local/api/v1/login has only 2, and doesn't have XSRF-TOKEN
scr2
Repox commented 4 years ago

Can you try and empty the SESSION_DOMAIN setting (to ensure that it's null and not an empty string)?

taiwanleaftea commented 4 years ago

I removed SESSION_DOMAIN from .env, so it should be null by default. Get CSRF token mismatch. with your nginx config.

Repox commented 4 years ago

I'm running out of ideas. What's the content of your app/Http/Kernel.php?

taiwanleaftea commented 4 years ago

On Monday I'll install the docker version, and will check difference in nginx.conf between my and docker version.

Kernel.php.txt

Repox commented 4 years ago

I don't think this is a nginx issue anymore. The "CSRF token mismatch" mismatch error indicates that you are providing a different X-XSRF-TOKEN than what Laravel is expecting. It's most likely something with your session configuration, but exactly what it is, is difficult for me to say.

Can you provide the VirtualBox image (if not a Vagrant provisioning)? I'm intrigued as to figuring out what's going on.

You are just running the hub locally with NPM and accessing at http://localhost:3000, right? No virtual environment for the hub?

mariapaulinar commented 4 years ago

Any solution?

imknight commented 3 years ago

update config/cors.php to set supports_credentials = true solved this for me

alecritson commented 3 years ago

Sounds like this can be resolved with the suggestion above, ultimately it doesn't seem like an issue with the hub, more to do with API configuration. Closing for now but feel free to reopen if you feel this needs further work.