Skip to content
This repository has been archived by the owner on Nov 30, 2022. It is now read-only.

Cookies on embedded apps blocked by Chrome 80 #367

Closed
jedimdan opened this issue Jan 7, 2020 · 18 comments · Fixed by #382
Closed

Cookies on embedded apps blocked by Chrome 80 #367

jedimdan opened this issue Jan 7, 2020 · 18 comments · Fixed by #382

Comments

@jedimdan
Copy link
Contributor

jedimdan commented Jan 7, 2020

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
Copy link
Contributor Author

jedimdan commented Jan 7, 2020

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
Copy link
Contributor Author

jedimdan commented Jan 9, 2020

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
Copy link
Contributor Author

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

@ptcampbell
Copy link

Thank you @jedimdan !

@StefanNeuser
Copy link

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
Copy link
Contributor Author

@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.

@jedimdan jedimdan changed the title Default cookie settings causes embedded app auth to go into redirect loop on Chrome 80 Cookies on embedded apps blocked by Chrome 80 Jan 16, 2020
@Kyon147
Copy link
Collaborator

Kyon147 commented Jan 17, 2020

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

shopify

@mferrario
Copy link

@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 get a 419 | Page Expired page.

I have tried this on both Chrome and Firefox.

Any insight would greatly be appreciated.

Thanks again.

@jedimdan
Copy link
Contributor Author

@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
Copy link
Contributor

See #382 for a fix

@jedimdan
Copy link
Contributor Author

@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
Copy link

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
Copy link
Collaborator

Kyon147 commented Feb 3, 2020

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
Copy link
Contributor Author

jedimdan commented Feb 3, 2020

@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
Copy link

mnatsakanyan commented Feb 3, 2020

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

@mnatsakanyan
Copy link

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
Copy link
Contributor Author

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
Copy link
Contributor Author

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.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
7 participants