DEV Community

Zubair Mohsin
Zubair Mohsin

Posted on

Dealing with Chrome SameSite cookie attribute in Shopify Apps made with PHP/Laravel

Prerequisite

Read this extensive tutorial from Shopify to get more understanding about the SameSite cookie attribute.

Working with SameSite cookie attribute

Read it? ðŸĪ“

Make sure you understand the problem! 🙌🏞

Oh you are sure? 👀

So what should be the value of SameSite attribute and what other attribute that you need to set to get it working? ðŸĪ”

Did you answer the above question correctly? 🧐

How would I know ðŸĪŠ

Let's continue 😌

Solution

You need to set SameSite=None and always pair it another attribute, Secure=true.

PHP Implementation

setcookie('cross-site-cookie', 'bar', ['samesite' => 'None', 'secure' => true]);
Enter fullscreen mode Exit fullscreen mode

Example link

Laravel implementation

Laravel has a session.php config file. In this file you can find these attributes and set their values as following:

///

'secure' => env('SESSION_SECURE_COOKIE', true),

///

'same_site' => 'none',
Enter fullscreen mode Exit fullscreen mode

Important! It will set these attributes for all cookies.

Simple, right? Well, No!!

So, what's the Catch?

Not all browsers support SameSite=None attribute. There are known incompatibilities.

List of incompatible browsers

Setting SameSite and Secure attributes for only compatible clients

  • If you are using ohmybrew/laravel-shopify package to develop your Shopify App, just upgrade this package to 10.3.1 and you are covered.
  • In order to detect the Browser client details in PHP, we can leverage jenssegers/agent package.
     /**
     * Sets the cookie policy.
     *
     * Enables SameSite none and Secure cookies on:
     *
     * - Chrome v67+
     * - Safari on OSX 10.14+
     * - iOS 13+
     * - UCBrowser 12.13+
     *
     * @return null
     */
    public function setCookiePolicy()
    {
        if ($this->checkSameSiteNoneCompatible()) {
            config([
                'session.secure'    => true,
                'session.same_site' => 'none',
            ]);
        }
    }

    /**
     * Checks to see if the current browser session should be
     * using the SameSite=none cookie policy.
     *
     * @return bool
     */
    private function checkSameSiteNoneCompatible()
    {
        $compatible = true;

        $this->agent = new Agent();

        $browser = $this->getBrowserDetails();
        $platform = $this->getPlatformDetails();

        if ($this->agent->browser() == 'Chrome' && $browser['float'] < 67) {
            $compatible = false;
        }

        if ($this->agent->is('iOS') && $platform['float'] < 13) {
            $compatible = false;
        }

        if ($this->agent->is('OS X') &&
            ($this->agent->browser() == 'Safari' && !$this->agent->is('iOS')) &&
            $platform['float'] < 10.15
        ) {
            $compatible = false;
        }

        if ($this->agent->browser() == 'UCBrowser' &&
            $browser['float'] < 12.132
        ) {
            $compatible = false;
        }

        return $compatible;
    }

    /**
     * Returns details about the current web browser.
     *
     * @return array
     */
    private function getBrowserDetails()
    {
        $version = $this->agent->version($this->agent->browser(), Agent::VERSION_TYPE_FLOAT);

        return [
            'float' => ($version ?: 0),
        ];
    }

    /**
     * Returns details about the current operating system.
     *
     * @return array
     */
    private function getPlatformDetails()
    {
        $version = $this->agent->version($this->agent->platform(), Agent::VERSION_TYPE_FLOAT);

        return [
            'float' => ($version ?: 0),
        ];
    }
Enter fullscreen mode Exit fullscreen mode

Snippet Source

Conclusion

  • This is how you can make your Embedded Shopify Apps made with PHP/Laravel work with SameSite cookie attribute and be ready for this change.

Let me know in comments if I missed something or there is a better solution.

Top comments (11)

Collapse
 
rowan_m profile image
Rowan Merewood

Nice article! For the benefit of anyone reading who didn't take your advice and fully understand the issues first ;) Please, please, please remember you ONLY need SameSite=None; Secure for cookies that are sent in cross-site / third-party contexts. So, that means these embedded apps or services. Cookies for first-party use, i.e. the domain in the browser matches the domain of the cookie, then consider SameSite=Lax or SameSite=Strict instead. Do not just blindly add SameSite=None; Secure to every single cookie.

Collapse
 
jasperf profile image
Jasper Frumau

So for the Laravel session and XSRF Token cookies we should use SameSite="Strict at config/session.php? How would we implement this and only have this apply for these two cookies I am now getting warnings for?

cookie `host-name_staging_session` will be soon rejected because it has
 the “sameSite” attribute set to “none” or an invalid value, without the “secure” attribute. To know more about the “sameSite“ attribute, read
 https://developer.mozilla.org/docs/Web/HTTP/Headers/Set-Cookie/SameSite 1748
Collapse
 
rowan_m profile image
Rowan Merewood

I'd suggest Lax for your session cookie, not Strict.

Collapse
 
dasdaniel profile image
Daniel P ðŸ‡ĻðŸ‡Ķ • Edited

Very timely post :) Just wanted to note some of my findings.

Chrome 80, as it's being updated across our computers, likely does not break your site/app.

Due to the safari bug, they put in an exception

Chrome will make an exception for cookies set without a SameSite attribute less than 2 minutes ago.

(link: chromestatus.com/feature/508814734...)

However, Safari seems to have been broken for a while now, so a fix should be implemented quickly.

(link: bugs.webkit.org/show_bug.cgi?id=19...)

Their solution uses an Apache regex to solve the problem, but the solution is not up to date with latest Safari.

On a side note, if you've using an SPA and JWTs (no cookies) this is a non-issue.

Collapse
 
rowan_m profile image
Rowan Merewood

That exception is temporary and will go away at some point. The specific situation that covers is for top-level, cross-site POST requests that require cookies. These should be set with SameSite=None; Secure as a permanent fix, not rely on the exception. This was added to account for a number of individual single sign-on implementations using this pattern to receive a CSRF token in their cookie - it is not related to the Safari issue.

The Safari issue is due to their implementation matching a much earlier version of the draft. As a result, if you need the cookie to work in all browsers you can use the double cookie solution proposed in web.dev/samesite-cookie-recipes/#h...

Collapse
 
zubairmohsin33 profile image
Zubair Mohsin

Thank you Rowan for your input on this issue 🙏🏞

Collapse
 
zubairmohsin33 profile image
Zubair Mohsin

Hi Daniel, thank you for sharing your findings.

SameSite flag is not being enforced even in Chrome 80 until 17th February, 2020. ( I am not sure about the date ) as a relaxation.

If you want to test, go to chrome://flags and enable all three SameSite flags. You will see the errors mentioned in Shopify's tutorial.

All we can do, is to be prepared, right? ;)

And yeah, you are right about SPA. 👍

Let me know your thoughts! Thanks.

Collapse
 
orrd profile image
David Orr

Why is it necessary to check the browser and only set the SameSite/Secure attributes for compatible clients? Would something bad happen if you just set it in your config/session.php and used it for all users? Any clients that do not recognize SameSite=None should ignore it and carry on as if the attribute was not set.

Collapse
 
wajahatanwar profile image
Wajahat Anwar

This tutorial was super helpful and it is straight and to the point. Thanks, Mohsin for sharing this.

Collapse
 
wajahatanwar profile image
Wajahat Anwar

One more thing I discovered. We can't set SameSite = None in laravel 5.6 or lower version. SameSite = Lax works in laravel 5.6 But we can set SameSite = NONE in 5.8 or above.

Collapse
 
jayshopto profile image
jayShopTO

Thank you for making this and helping the community.