gnikyt / laravel-shopify

A full-featured Laravel package for aiding in Shopify App development
MIT License
1.24k stars 374 forks source link

Cookies on embedded apps blocked by Chrome 80 #367

Closed jedimdan closed 4 years ago

jedimdan commented 4 years ago

Expected Behavior

Successfully authenticate embedded app on Chome 80.

Current Behavior

Shopify store goes into a redirect loop as the cookies from the app are rejected by Chrome 80.

Steps to Reproduce

  1. Install Chrome Beta
  2. Launch the app within the Shopify store
  3. The app would not authenticate successfully.

Context

Come February 2020, Chrome 80 will be released and will begin rejecting cookies from a third party site that is not set to SameSite=None; Secure. (Ref: Chromium blog) According to Google, Mozilla and Microsoft will be making the same changes in future versions of their browser.

As embedded apps on Shopify are considered third-party, if the app's cookie is not set to SameSite=None; Secure, the behaviour described above would occur. To further complexify things, Safari on macOS 10.14 and iOS 12 (and some others) would behave incorrectly when a cookie with SameSite=None; Secure is submitted. As such, the app needs to not send that flag to some of these browsers. In other words, simply setting the cookies config in Laravel would not be sufficient.

While this is a Laravel thing more than an issue with this package (Laravel supports setting these flags on cookies via session.php), all projects that use this package to develop embedded apps on Shopify would encounter this issue. So perhaps it could be something this package could handle?

Thought to bring this up as a topic of discussion. I'm open to contribute code to this but would love to hear your thoughts first, especially from @ohmybrew.

Additional Reference: Shopify article about this issue

jedimdan commented 4 years ago

My suggestion is to create a middleware that would detect the user agent, and based on a blacklist, decide who should not receive the SameSite: None; Secured flag in a cookie.

jedimdan commented 4 years ago

In the meantime, as Chrome 80 is going to be released in less than a month, I've implemented this middleware to my app and added it to the list of global middlewares.

jedimdan commented 4 years ago

Shopify is working to upgrade its app Rails library and it looks like their strategy is to also introduce a middleware https://github.com/Shopify/shopify_app/pull/851. Perhaps we could employ the same strategy?

ptcampbell commented 4 years ago

Thank you @jedimdan !

StefanNeuser commented 4 years ago

Thanks @jedimdan , if you use the X-Shop-xxx headers in case you are using XHR-Request's for post-data (or SPA) than everythink is working (https://github.com/StefanNeuser/laravel-shopify/blob/3ca33250ad9506a4d985d490bb3d63025c9b6066/src/ShopifyApp/Middleware/AuthShop.php#L252)

At the moment we want to have a more general approch to promote this variables because at the moment we are hard-coding all known parameters like

window.axios.defaults.headers.common['X-Shop-Domain'] = document.head.querySelector('meta[name="shop"]').content
window.axios.defaults.headers.common['X-Shop-Signature'] = document.head.querySelector('meta[name="hmac"]').content
window.axios.defaults.headers.common['X-Shop-Time'] = document.head.querySelector('meta[name="timestamp"]').content
window.axios.defaults.headers.common['X-Shop-Locale'] = document.head.querySelector('meta[name="locale"]').content
window.axios.defaults.headers.common['X-Shop-State'] = document.head.querySelector('meta[name="state"]').content
window.axios.defaults.headers.common['X-Shop-Code'] = document.head.querySelector('meta[name="code"]').content
window.axios.defaults.headers.common['X-Shop-ID'] = document.head.querySelector('meta[name="id"]').content
window.axios.defaults.headers.common['X-Shop-IDs'] = document.head.querySelector('meta[name="ids"]').content
window.axios.defaults.headers.common['X-Shop-Session'] = document.head.querySelector('meta[name="session"]').content

that comes from

    <meta name="shop" content="{{ request()->input('shop') }}">
    <meta name="hmac" content="{{ request()->input('hmac') }}">
    <meta name="timestamp" content="{{ request()->input('timestamp') }}">
    <meta name="code" content="{{ request()->input('code') }}">
    <meta name="locale" content="{{ request()->input('locale') }}">
    <meta name="state" content="{{ request()->input('state') }}">
    <meta name="id" content="{{ request()->input('id') }}">
    <meta name="ids" content="{{ request()->filled('ids') ? '["'.implode('", "', request()->input('ids')).'"]' : '' }}">
    <meta name="session" content="{{ request()->input('session') }}">

We want to iterate to all request params when the app becomes open and also search for them like

document.head.querySelector('meta[name="shopify-param-*"]').content

jedimdan commented 4 years ago

@StefanNeuser i think you might have confused this issue with #359, as this issue is referring to the flags that accompany the app’s cookies rather than the verification of the request. In this issue, the app goes into an auth loop because it thinks it’s not even authenticated due to Chrome blocking all cookies from this app, therefore the app is not able to identify the session of the request. Without a session, the app will attempt to login again which results in an infinite loop. This is caused by a change in how Chrome will treat cookies.

Kyon147 commented 4 years ago

Just to update, got this email today as most of us probably did.

shopify

mferrario commented 4 years ago

@jedimdan Thanks for the solution. However, I am having trouble getting it to work on a fresh install. I am running Laravel 5.6, php 7.2 and I am running dev-master (due to the other auth issue). I am somewhat new to Laravel, so may be doing something wrong.

Here is my repo steps:

Setup:

  1. Created a new middlewear php artisan make:middleware SameSiteNone
  2. Installed the jenssegers/agent (composer and then followed the Laravel instructions)
  3. Added '\App\Http\Middleware\SameSiteNone::class,' to Kernel.php in the Global HTTP array.
  4. Pushed to production (AWS - Beanstalk)
  5. Go to: domain.com/login
  6. Enter myshopname.myshopify.com

Actual Result:

I have tried this on both Chrome and Firefox.

Any insight would greatly be appreciated.

Thanks again.

jedimdan commented 4 years ago

@mferrario I'm afraid I'm not really sure what you're experiencing. I don't think the 419 is caused by this bug or the middleware as all my middleware did is change the config for sessions.

darrynten commented 4 years ago

See #382 for a fix

jedimdan commented 4 years ago

@darrynten in the meantime, since we are not sure if the PR will be merged and released in time, would manually creating a middleware like to an app like what I suggested above be workable as a temporary solution?

mnatsakanyan commented 4 years ago

According to #382, what I need to do if I only used "ohmybrew/laravel-shopify": "^6.0" in my laravel project and I have created Shopify app? composer update does't created ShopSession.php in to vendor/ohmybrew/laravel-shopify/src/ShopifyApp/Services folder

Thanks!

Kyon147 commented 4 years ago

According to #382, what I need to do if I only used "ohmybrew/laravel-shopify": "^6.0" in my laravel project and I have created Shopify app? composer update does't created ShopSession.php in to vendor/ohmybrew/laravel-shopify/src/ShopifyApp/Services folder

Thanks!

Have you tried to clear the cache first?

composer clear-cache
composer update

Sometimes it is also better just to update the package directly.

composer update ohmybrew/laravel-shopify

jedimdan commented 4 years ago

@mnatsakanyan you'll need to update your composer.json file to say "ohmybrew/laravel-shopify": "^10.0" instead because your current constraint does not allow the package to update beyond v6. You can read more about the ^ symbol on the composer documentation if you'd like to learn more.

mnatsakanyan commented 4 years ago

Thanks @jedimdan after change to "^10.0" it works.

mnatsakanyan commented 4 years ago

In Chrome 80 it is works, but in Chrome 79 version I can't login with Laravel Auth. Also I got "Unable to get shop domain." when I trying to open my shopify app. Now I am using "ohmybrew/laravel-shopify": "^10.2.1"

jedimdan commented 4 years ago

Just FYI that the SameSite behaviour is not going to roll out at once to everyone.

February, 2020: Enforcement rollout for Chrome 80 Stable: The SameSite-by-default and SameSite=None-requires-Secure behaviors will begin rolling out to Chrome 80 Stable for an initial limited population starting the week of February 17, 2020, excluding the US President’s Day holiday on Monday. We will be closely monitoring and evaluating ecosystem impact from this initial limited phase through gradually increasing rollouts.

Ref: https://www.chromium.org/updates/same-site (Launch Timeline)

If you'd like to force your browser to enable the new behaviour, you can enable the flags on your browser:

To test the effect of the new Chrome behavior on your site or cookies you manage, you can go to chrome://flags in Chrome 76+ and enable the “SameSite by default cookies” and “Cookies without SameSite must be secure” experiments.

Ref: https://blog.chromium.org/2019/10/developers-get-ready-for-new.html

jedimdan commented 4 years ago

In addition to that, in Chrome 80's dev tools network tab, after the requests have loaded in the tab, you'll find a new "Only show requests with SameSite issues" checkbox next to the list of filters. That's probably the easiest way to look out for problematic responses.