Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

google_oauth2 Authentication failure! csrf_detected: OmniAuth::Strategies::OAuth2::CallbackError, csrf_detected | CSRF detected #58

Closed
gdurelle opened this issue May 19, 2014 · 67 comments

Comments

@gdurelle
Copy link

Even when creating the state myself it got the same error.

session['omniauth.state'] =  SecureRandom.hex(24)
redirect_to "/auth/google_oauth2?state=#{session['omniauth.state']}"

Even though the returned state is the same, meaning it should match !

Isn't there a double redirect or something ?
Because if so the :

request.params['state'] != session.delete('omniauth.state')

in https://github.com/intridea/omniauth-oauth2/blob/master/lib/omniauth/strategies/oauth2.rb#L72 would explain the problem.
=> First passes, second fail.

https://stackoverflow.com/questions/22386149/why-am-i-getting-csrf-detected-with-omniauth-and-google/23739564#23739564

@gdurelle gdurelle changed the title google_oauth2) Authentication failure! csrf_detected: OmniAuth::Strategies::OAuth2::CallbackError, csrf_detected | CSRF detected google_oauth2 Authentication failure! csrf_detected: OmniAuth::Strategies::OAuth2::CallbackError, csrf_detected | CSRF detected May 19, 2014
@guilhermesimoes
Copy link
Contributor

OmniAuth already creates the state for you, why are you trying to override it?

Also, when you run bundle show, what is the version of the omniauth-oauth2 gem?

@gdurelle
Copy link
Author

I don't. it was to be sure the state token was the same (through loggers).

bundle show omniauth-oauth2
/usr/local/var/rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/omniauth-oauth2-1.1.2

@guilhermesimoes
Copy link
Contributor

This should be working out of the box.

In what specific omniauth gem is this happening? How are you configuring it?

@gdurelle
Copy link
Author

Just omniauth with google_oatuh2 provider.

Rails.application.config.middleware.use OmniAuth::Builder do
  provider :google_oauth2, Settings.google_oauth2.app_id, Settings.google_oauth2.app_secret, {
    prompt: 'select_account',
    image_aspect_ratio: 'square',
    image_size: 200
  }
end

@guilhermesimoes
Copy link
Contributor

I think you made a copy paste mistake, Flm.config( should throw some kind of syntax error.

Either way, make sure that Settings.google_oauth2.app_id and Settings.google_oauth2.app_secret are working. Double check those tokens.

@gdurelle
Copy link
Author

lol yeah. fixed ;)

Well everything works fine when I use the ugly

provider_ignores_state: true

option.
Thus I'm sure my credentials are ok.

For the record I also use other options, but quite sure it has nothing to do with the present problem :

    prompt: 'select_account consent',
    access_type: 'offline',
    scope: 'userinfo.profile,userinfo.email,youtube'

@guilhermesimoes
Copy link
Contributor

Yeah, this issue shouldn't have anything to do with your configuration. However, given OmniAuth's history of catching client errors and throwing random errors, I wouldn't dismiss this just yet.

When you run bundle show, what is the version of the omniauth-google-oauth2 gem? Try changing the scopes userinfo.profile and userinfo.email just to profile and email. They were recently deprecated.

@gdurelle
Copy link
Author

/usr/local/var/rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/omniauth-google-oauth2-0.2.3
scopes changed. same error.

Started GET "/auth/google_oauth2/callback?state=e044e048e1058afa01ec0b77f01f16507dcd23f850a5e18d&code=4/XDJgOYYMDkZmKH4074eZSTFHUSbI.kgC2pBqj6B0ZYKs_1NgQtmW_GcM7jAI" for 127.0.0.1 at 2014-05-21 10:22:19 +0200
(google_oauth2) Callback phase initiated.
(google_oauth2) Authentication failure! csrf_detected: OmniAuth::Strategies::OAuth2::CallbackError, csrf_detected | CSRF detected

@jdenquin
Copy link

jdenquin commented Jun 6, 2014

After some tests, its appear that session['omniauth.state'] is nil during the callback phase!
Why session doesn't keep it?

@vincent-pochet
Copy link

This problem occurs with rails when the domain defined in /config/initializer/session_store.rb is different from the origin/redirect_uri defined in the google api console.

MyApp::Application.config.session_store :cookie_store, key: '_app_session', domain: 'my_app.com'

Removing the domain params or using the same domain on both sides (plus activating contacts and google+ APIs in console...) fixed the problem for me.

I think we can close this issue! 😸

@iamasecuritytester
Copy link

I had this exact same problem and adding domain: 'localhost' in session_store.rb fixed it for me. Thanks everyone!

@NickTomlin
Copy link

I'm running into this in a Sinatra app using omniauth-google-oauth2. I've added the redirect url through the control panel api, but to no avail. They only way around it at the moment is provider_ignores_state but that feels wrong.

@gdurelle gdurelle closed this as completed Aug 7, 2014
@dentarg
Copy link

dentarg commented Aug 7, 2014

@gdurelle why close?

On 7 aug 2014, at 10:54, Gregory Durelle [email protected] wrote:

Closed #58.


Reply to this email directly or view it on GitHub.

@gdurelle
Copy link
Author

gdurelle commented Aug 7, 2014

See comments above, seems it's just a domain problem; besides the provider_ignores_state: true
solution should only be temporary on a dev env, because it introduces security issues.

I'm closing because it's no longer an issue. At most a configuration need, badly documented.

But if you think there's a real technical problem, i'll reopen it right away.

@dentarg
Copy link

dentarg commented Aug 12, 2014

@gdurelle Thanks for clarifying.

I ran into the same problem with omniauth-github, and provider_ignores_state: true "fixed" it, but as @NickTomlin wrote above, using provider_ignores_state: true feels wrong. But I haven't had time to look into the problem more. I don't think there's a need to reopen.

@daniel-nelson
Copy link

I have been wrestling with this all day, but none of the above helped.

I finally realized that this is happening to me on staging because staging is at staging.example.com and production is at example.com, so both production and staging cookies are being sent to staging. Staging will work most of the time, but then if I go use production and come back to staging, I get one more valid request and then need to re-authenticate. After returning from authenticating with Google, it threw csrf_detected until I cleared cookies. It would then work fine until some seemingly random time in the future that I now attribute to my having interacted with production.

I'm leaving this note here because Google kept leading me back to this issue, so perhaps it will help someone else.

@valo
Copy link

valo commented Aug 25, 2014

I was getting this error in a rails app and the way to reproduce it was to initiate two oauth2 logins at the same time. This caused one of the logins to fail with CSRF error, because its random string in the state params get invalidated by the second login request.

Just something to keep in mind if you get this error from time to time and you can't figure out why.

@N0hbdy
Copy link

N0hbdy commented Sep 10, 2014

Hey all,

I'd just like to point out that this is still broken under some conditions: namely, if you start making multiple requests from you're app, and during that time initiate an auth request, there's a race condition that causes the session cookie that holds the state to be clobbered.

Specifically,
-Request 1 for some resource hits you're server, and begins doing something that requires a lot of computation/lookups.
-Auth request is created
-Auth request (with state information) is returned, cookie is updated
-Request 1 returns, cookie is overwritten by Request 1's cookie (which didn't have the session state in it)
-User finishes authorizing with 3rd party, callback is initiated, and request.params['state'] is empty

Just wanted to add to the thread, as I wound up here after some quick googling as well. I solved this by doing something specific within my app space (message if you'd like to hear what, but its more of a case-by-case thing) - if theres something I'm missing though that would have solved this would love to hear it!

@joshco
Copy link

joshco commented Oct 21, 2014

Strangely, I'm seeing this on iOS safari, but not iOS chrome or mac/pc
im using facebook omniauth

@raldred
Copy link

raldred commented Oct 26, 2014

@gdurelle even with the session domain set this does not work.
We need to work out a proper solution for development.

@austinwang
Copy link

For whatever its worth , I had all these issues because I had my clientId and secret in both my omniauth.rb file as well as my devise.rb config file. I mistakenly did this following the omniauth-google-oauth2 gem instructions. Now I only have the line below in devise.rb.
config.omniauth :google_oauth2, client, secret

No omniauth.rb file needed.

@raldred
Copy link

raldred commented Oct 27, 2014

@austinwang wow! i gave up and moved to using the gplus provider.
How stupid of me, that was the issue. Such a school boy error.
Thanks

@Uelb
Copy link

Uelb commented Nov 15, 2014

@austinwang +1
I removed the wrong initializer and it works now !

@ilanwei1
Copy link

ilanwei1 commented Dec 2, 2014

@daniel-nelson - nice catch

@valk
Copy link

valk commented Dec 17, 2014

@daniel-nelson - thanks!
Clearing the freaking cookies in Chrome solved the problem.

@danwiding
Copy link

Is this issue related to google issue https://code.google.com/p/gdata-issues/issues/detail?id=6628 wherein occasionally two requests are sent back from google account login?

@wazery
Copy link

wazery commented Sep 22, 2016

It's weird that it redirects me to the correct GitHub application, and asks me to authorize, hence the credentials are correct. Weird that this error is in the callback phase.

Something to mention, I don't have this error locally.

Update: I managed to fix my issue, it wasn't related to this GitHub issue.

@cjbutcher
Copy link

cjbutcher commented Oct 27, 2016

I had a really bad time with this error and wanted to leave a comment to help out anyone in the same situation. I was specifically using an omniauth-github strategy.

In the controller action that renders the view with your authentication link on it, include the line:

session['omniauth.state'] = SecureRandom.hex

And in the link itself, include that session key as a query parameter called 'state'. I put this method in application helper so I could call it from the view:

  def github_auth_url
    "https://github.com/login/oauth/authorize?scope=user:email&client_id=" + Rails.application.secrets.github_client_id + '&state=' + session['omniauth.state']
  end

@marcusmalmberg
Copy link

I also had a problem with this and by chance I found out that visitors using naked domain (non-www) got this error.

After some digging I found the source to my problem:

  • the callback_url was set to the www subdomain
  • the session_store used default domain settings (which resulted in that different cookies were used for www and naked)
  • since the user came from naked domain the session was initiated there, but when the callback came back it was to the www subdomain. Since we didn't have a session we didn't get a match, thus failing.

There are a few different solutions to this:

  • Configure session_store to use the same cookie for both naked and www
  • Redirect all traffic to either www or naked (and adjust the callback_url to match it)
  • Make the callback_url aware of which subdomain should be used

I went with redirecting the traffic to www, since it was better suited for my given situation. There are multiple ways to redirect the traffic, e.g using Rails routes:

# config/routes.rb
constraints subdomain: false, domain: 'mydomain.com' do
  get ':any', to: redirect(subdomain: 'www', path: '/%{any}'), any: /.*/
end

@gotno
Copy link

gotno commented Jun 8, 2017

i've been banging my head against this issue for far too long to not leave a comment here letting others know what worked for me.

for context: i'm using oauth within a mounted rails engine. the issue was that the main rails app the engine was mounted in was using https via force_ssl but the engine was not. this caused the server to randomly bounce between http and https, which both caused the csrf error and trashed the session.

if you're reading this, i hope it helps you to not lose two and a half days to debugging like i did. godspeed!

@samratjp
Copy link

FWIW, if anyone else comes here with the same issue - I had the same error happen with Hybrid Auth; adding provider_ignores_state in omniauth setup fixed it.

Then another separate bug appeared with invalid_client; which was way more easier to handle - PEBKAC :)

@eddiej
Copy link

eddiej commented Sep 26, 2017

With the hybrid auth approach, it seems that the state is never set locally (usually done at https://github.com/intridea/omniauth-oauth2/blob/master/lib/omniauth/strategies/oauth2.rb#L58). Anyone know if its safe to set provider_ignores_state to true if the hybrid approach is used?

@xiaohui-zhangxh
Copy link

If you got this error with Safari, then try Firefox and Chrome. If only Safari has this issue, then my answer may help, because I spend hours to figure it out.

The problem is, like this URL http://example.org/auth/my-strategy, Safari will send two requests.

The first request to onmiauth, will generate a state, then redirect to my-strategy login, after login successfully, redirect back to my-strategy callback http://example.org/auth/my-stragegy/callbck with s state parameter, at this time Omniauth will compare the state value between session and callback parameter.

The second request is going after the first request, it makes Omniauth generate another state.

See, the callback state param of the first request has not to be the same of state in session, that's why we got CSRF detected error.

To fix it, I add a timestamp to login URL, http://example.org/auth/my-strategy?t=12345678, Safari won't request this URL twice when I click it.

@SirRawlins
Copy link

I found this issue myself today, and thanks to @N0hbdy's suggestion. I had a regular AJAX ping going on in the browser which was firing at a similar time as the navigation to the /auth path, creating a race condition which was dirtying the session.

Ended up aborting and unbinding the AJAX request on page unload to prevent the race.

@ginjo
Copy link

ginjo commented Aug 3, 2018

@marcusmalmberg , your post solved it for me!

If working with multiple domains, you will have different session cookies. So if you use callback_url (or redirect_uri), you need to work out your domains/subdomains so that you have a valid session during the callback phase. No more csrf_error 😄 .

@LiinNs
Copy link

LiinNs commented May 28, 2019

here is my way
provider :provider, APP_KEY, APP_SECRET, provider_ignores_state: Rails.env.development?

VitaliyAdamkov added a commit to VitaliyAdamkov/solidus_social that referenced this issue Jun 14, 2019
VitaliyAdamkov added a commit to VitaliyAdamkov/solidus_social that referenced this issue Jun 14, 2019
@0xtobit
Copy link

0xtobit commented Jun 24, 2019

Changing localhost to 127.0.0.1 in my redirect_uri and it was fixed for me.

@seigel
Copy link

seigel commented Dec 31, 2019

Not sure if this will help anyone, but I had multiple unicorn workers and I believe each one had a different session secret because of me using SecureRandom.hex to set them. I believe if the request came back to a different worker, then I get some weird CSRF token error. It would work if it hit the same worker. Using a session value shared between the workers seems to give me better results: set :sessions, secret: ENV["SESSION_SECRET"]

I am using Sinatra, and unicorn currently.

@randall-coding
Copy link

randall-coding commented Apr 8, 2020

I just had the same issue. Not sure what the state parameter has to do with csrf but that is what caused the issue.

I had tried creating the link like so
google_oath2_calendar_authorize_url (state:{interview_token: token})
which yields: /users/auth/google_oauth2_calendar?state[interview_token]= lS_Jj_Clkf6s3ggLzlSDBb3IwNVDN9DhxJe6yy2T
which is valid rails syntax I believe, but that caused the error for me.

Instead creating the link like this works for me
google_oath2_calendar_authorize_url + '?state=' + URI.encode({interview_token: token}.to_json)

@patrickdavey
Copy link

Unrelated to the above, but, I just ran into this issue and googling brought me here.

My issue was that on staging I was using authenticate_or_request_with_http_basic as a block for robots etc. if they happen to stumble across our site.

The weird thing which I don't understand yet is that if a user went directly to the url which then issued a redirect to the auth/provider endpoint it would ultimately end up with a csrf_detected error.

If however the user first went to any other page to get past the authenticate_or_request_with_http_basic and then went to the page which did the redirect - it would all work fine.

I don't quite understand why the authenticate_or_request_with_http_basic would cause this issue, but, it definitely does for me.

@dmz006
Copy link

dmz006 commented May 11, 2020

This problem occurs with rails when the domain defined in /config/initializer/session_store.rb is different from the origin/redirect_uri defined in the google api console.

MyApp::Application.config.session_store :cookie_store, key: '_app_session', domain: 'my_app.com'

Removing the domain params or using the same domain on both sides (plus activating contacts and google+ APIs in console...) fixed the problem for me.

I think we can close this issue!

Things were working fine for google & facebook but I couldn't get twitter/github or linkedin oauth working. I found lots of ways people tried to fix this but in the end it was because I had upgraded an old app to rails 5 and the cookie session store that was a default initializer was removed in rails 5 and built into the app. You can still override it which I think was causing a conflict in the domain used.

If you are running into this problem with an app that was upgraded from 4->5 try commenting out Rails.application.config.session_store in the session_store.rb initializer and see if it helps.

rails/rails@e5a6f7e

@ajeygore
Copy link

For whatever its worth , I had all these issues because I had my clientId and secret in both my omniauth.rb file as well as my devise.rb config file. I mistakenly did this following the omniauth-google-oauth2 gem instructions. Now I only have the line below in devise.rb.
config.omniauth :google_oauth2, client, secret

No omniauth.rb file needed.

That was a saviour, thank you :-) so people who just do google auth with google-omniauth and then change their mind putting devise in mix, will end up in this situation.

@dwram
Copy link

dwram commented Sep 3, 2020

For whatever its worth , I had all these issues because I had my clientId and secret in both my omniauth.rb file as well as my devise.rb config file. I mistakenly did this following the omniauth-google-oauth2 gem instructions. Now I only have the line below in devise.rb.
config.omniauth :google_oauth2, client, secret

No omniauth.rb file needed.

This resolved it for me!

@thatguysimon
Copy link

thatguysimon commented Feb 28, 2021

For me the reason this happened was non of the above so I thought I'd share what solved it for me. Maybe it can save someone else a few hours of headache in the future.

Following this change introduced in Google Chrome behavior, we started adding SameSite=None to all Set-Cookie headers.
But, Chrome also ignores Set-Cookie headers that have SameSite=None but are missing the Secure attribute.
And, since I was running this on localhost, without HTTPS, the Secure attribute was not added.

So as a result, my session cookie wouldn't get created on the browser because Chrome would ignore its Set-Cookie header, resulting in a new session created on each request, and a failed state comparison.

So if your app is setting SameSite=None to the session's Set-Cookie header like this or for all cookies with this gem or this gem, and you're getting this error when running locally, you should do one of the following:

  • In chrome://flags/, disable "Cookies without SameSite must be secure"

Or

  • Configure your localhost to run in HTTPS.

Hope this helps.

Update (Nov 25th 2021):

@willy-wonka-git
Copy link

willy-wonka-git commented Nov 14, 2021

Clear coockies helped me

@gingerlime
Copy link

Having a similar issue after upgrading to Rails 7, and only with Safari. Firefox/Chrome work fine. Really bizarre. Any tips on how to troubleshoot / fix this?

@omniauth omniauth locked as resolved and limited conversation to collaborators Jun 22, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests