omniauth / omniauth-oauth2

An abstract OAuth2 strategy for OmniAuth.
MIT License
500 stars 304 forks source link

omniauth: (google_login) Authentication failure! csrf_detected (only Safari) #155

Open gingerlime opened 2 years ago

gingerlime commented 2 years ago

We started getting reports from users that they cannot login with Google (it also happens with login with Facebook). On Firefox or Chrome it works fine, but does not work in Safari. It simply goes back to the login page.

I can see this error in our puma log:

E, [2022-06-22T11:54:57.979909 #40] ERROR -- omniauth: (google_login) Authentication failure! csrf_detected: OmniAuth::Strategies::OAuth2::CallbackError, csrf_detected | CSRF detected

Any suggestions on how to investigate/resolve this?

gingerlime commented 2 years ago

It seems like the problem started after we upgraded Rails from 6 to 7 (and also switched our asset compilation from sprockets to propshaft, but not sure if/how this is related). It's very odd however that it works with other browsers but only fails with Safari.

dentarg commented 2 years ago

Something with Intelligent Tracking Prevention? https://webkit.org/tracking-prevention/

BobbyMcWho commented 2 years ago

Make sure safari isn't set to block all cookies, and if you're on Rails 7, see if you need to make this change: https://github.com/omniauth/omniauth/issues/1061#issuecomment-1074426340

gingerlime commented 2 years ago

Thank you @dentarg and nice to bump into you again here. I also had a similar hunch, but not sure how this is affected by the version of Rails though? and I think Firefox also has its own tracking prevention by default? I don't see anything obvious being blocked by the browser though, but on the backend it indicates that there's a CSRF error. By the way, someone also wrote about Safari specifically back in 2017, although I couldn't work out what changes to make).

@BobbyMcWho that's very interesting. However, we're already using turbo => false with a form that POSTs rather than GET. I think we upgraded from Turbolinks to Turbo even before upgrading to Rails 7 though. And why only Safari? it's not blocking cookies and the same browser works with the codebase prior to upgrading to Rails 7 somehow.

BobbyMcWho commented 2 years ago

Does this only occur with google oauth, or other omniauth strategies as well?

I don't have a Rails 7 app to test this with unfortunately, can you submit a minimal app that reproduces this behavior?

I've got some single filers here that you could start off with

gingerlime commented 2 years ago

It also happens with Facebook. But as I mentioned, only with Safari.

I can try to create a reproducible app, but it might be tricky to include all the different moving parts that might affect this.

gingerlime commented 2 years ago

I found a workaround. I'm still not sure what it does or how, but it seems to solve the problem.

I changed our config/application.rb, from using config.load_defaults 7.0 to config.load_defaults 6.0 and then it works in Safari. Oddly, I also tried config.load_defaults 6.1 and it also fails. Our Rails 6 before the upgrade used config.load_defaults 6.0 even though we were on Rails 6.1.x

BobbyMcWho commented 2 years ago

Here's where that's defined in Rails. I suspect one these two blocks of settings [1, 2], I suspect it's the lax setting.

gingerlime commented 2 years ago

Interesting. The HN link is from early 2020 and still seems to be a problem. I tested on Big Sur with Safari Version 14.1.2 (16611.3.10.1.6).

Is there a better workaround then to only switch this back and still use the 7.0 defaults?

BobbyMcWho commented 2 years ago

You could switch back to set_defaults 7.0 and in an initializer set Rails.application.config.action_dispatch.cookies_same_site_protection = :strict which may help, but I suppose could break things depending on how your site is set up and what needs access to cookies.

gingerlime commented 2 years ago

It seems like with 6.0 defaults it is set to nil, so I can use Rails.application.config.action_dispatch.cookies_same_site_protection = nil ? not sure what the implications are. I will try to play around with it. Is there a long-term / stable solution that Omniauth can apply?

gingerlime commented 2 years ago

I tested with Rails.application.config.action_dispatch.cookies_same_site_protection = nil and it seems to work. With Rails.application.config.action_dispatch.cookies_same_site_protection = :strict it fails to login with Google on Safari but works with Firefox.

BobbyMcWho commented 2 years ago

Different browsers handle nil differently I believe. As far as I can tell, this isn't really an Omniauth issue, but more an application configuration issue, you may want to try :none instead of strict.

Out of curiosity, are you using cookie store for your sessions?

gingerlime commented 2 years ago

Thank you @BobbyMcWho. We store sessions in redis, although we are considering swiching to cookies.

BobbyMcWho commented 2 years ago

To be clear, I'm not sure if cookie store would resolve it for you or not, I'm happy to help if I can, but unfortunately I don't have first hand experience with this specific issue in a production app, so I'm unsure how to guide your resolution

gingerlime commented 2 years ago

Thanks again @BobbyMcWho. :none seems to cause some strange issues in our browser automation tests on our staging environment. Didn't dig into it. nil (which is the 6.0 default) seems to work however.

I'm also not sure what difference using cookies vs sessions make. We're using clearance for authentication, so perhaps the way they set up their cookies is different from how cookie store does it? any tips on what to look for and how to investigate this weird issue would be appreciated. It seems to stretch my knowledge quite a bit, especially since it fails on Safari, and only very broadly familiar with the mechanics of oauth2 either.