I have a Rails 6.1 app that uses sessions to store some data. When I open the app in an iFrame the sessions do not work (I cannot get their value when navigating to another page of the app, still inside the same iFrame)
I read a lot about this and played around with the cookies same_site configurations etc.
I also read about Chrome being the reason but I tried it in Safari with the same issue.
But I do not want to share sessions between the rails app and the page that contains the iFrame. I just want that the app works normally inside the iFrame.
Any ideas what could be the reason?
In order for your session cookie to work inside of an iframe, you need to explicitly set its SameSite setting to None.
Rails 6.1 introduced a new configuration option, which you can set e.g. in your config/application.rb:
config.action_dispatch.cookies_same_site_protection = :none
The relevant section on the guides is here.
Your best bet is most likely to use the rails_same_site_cookie gem.
Secure settingWhen setting SameSite to None, you must also ensure that your cookies are sent with the Secure setting set to true. This happens when you uncomment the following line in config/environments/production.rb:
config.force_ssl = true
The relevant commit for Rails 6.1 is here. It boils down to Rails now explicitly setting SameSite=Lax on every cookie it sends.
I have found that the best way to locally test a setup such as this one is to run a separate server (e.g. a Middleman instance) to simulate the third party page which embeds your Rails app in an iframe.
Then you can point one browser tab to localhost:3000/my/iframed/page, and the other to lvh.me:4567/my/embedding/page. You should be able to sign in one tab and act as the signed in user in the other.
It is crucial to also test this in a production-like environment.
None vs Lax vs StrictIf you were to set SameSite=Lax, this setup would only work when both tabs are pointing to the same domain, e.g. localhost. With SameSite=Strict, it would not work at all.
When you are testing this, if you switch from e.g. :lax back to :none, you will be logged out from both tabs.
Note that changing SameSite's value is not enough to set up your Rails app to work inside of an iframe. You also need to set the right headers in the relevant controller action, like so:
response.set_header("X-Frame-Options", "ALLOW-FROM #{embedding_url}")
response.set_header("Content-Security-Policy", "frame-ancestors 'self' #{embedding_url}")
Where embedding_url can be *, if you'd like anyone to be able to embed your Rails app via an iframe.
For further reading, the nice people over at makandra have compiled a card specifically about the SameSite setting.
There is nothing you can do to fix the problem in Safari—besides asking your users to uncheck the Prevent cross-site tracking checkbox in their preferences. In the future, the same is likely to apply to all major browsers (see here for the relevant Chrome blog post).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With