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

Authentication failure! csrf_detected #443

Open
donovanhubbard opened this issue May 5, 2023 · 9 comments
Open

Authentication failure! csrf_detected #443

donovanhubbard opened this issue May 5, 2023 · 9 comments

Comments

@donovanhubbard
Copy link

I'm setting up a single page application using react that has ruby on rails as the backend. I have my google api credentials and I have the front end sign in with google setup according to these instructions. https://developers.google.com/identity/gsi/web/guides/client-library

When I click the sign in button I can auth with google successfully and I'm redirected to the callback url. I have a controller method setup but the code is throwing an exception prior to running any of it. I get the following error message:

D, [2023-05-04T22:29:16.073195 #10561] DEBUG -- omniauth: (google_oauth2) Callback phase initiated.
E, [2023-05-04T22:29:16.076422 #10561] ERROR -- omniauth: (google_oauth2) Authentication failure! csrf_detected: OmniAuth::Strategies::OAuth2::CallbackError, csrf_detected | CSRF detected
Processing by Users::OmniauthCallbacksController#failure as HTML

I've narrowed the exception code down to these lines here. https://github.com/omniauth/omniauth-oauth2/blob/3a43234ab5dd36a75f9c125c58fcfe1a37b26805/lib/omniauth/strategies/oauth2.rb#L86-L87

Both !options.provider_ignores_state and request.params["state"].to_s.empty? evaluate to true. It looks like it's expecting a parameter called state but the POST request that google's javascript api is sending only contains the parameters credentials which contains a JWT and g_csrf_token.

Am I missing something here? Am I using the wrong libraries or something?

ruby version: 3.2.2

rails version: 7.0.4.3

devise gem 4.9.2

omniauth gem 2.1.1

omniauth-google-oauth2 gem 1.1.1

@viktor-shmigol
Copy link

I'm having the same error: csrf_detected.
I identified the problem and found it happens when I use the latest gem rack v3.0.8.
However, if I downgrade it to v2.2.8, it's working without an issue.

ruby version: 3.2.2
rails version: 7.1.1
omniauth-google-oauth2 version: 1.1.1
omniauth-rails_csrf_protection 1.0.1

I'm not sure, but it may be related to this gem as well: https://github.com/cookpad/omniauth-rails_csrf_protection

@zquestz
Copy link
Owner

zquestz commented Oct 26, 2023

Does any version of rack v3 work? Might want to add this to the docs.

@Gasol
Copy link

Gasol commented Dec 4, 2023

Does any version of rack v3 work? Might want to add this to the docs.

It is working for me on Rails 7.1 with Rack 3.0.8.

@viktor-shmigol
Copy link

It's working in the dev environment but does not in the Prod.
@Gasol Did you try it in the Production environment?

@Gasol
Copy link

Gasol commented Dec 4, 2023

@viktor-shmigol The project I am working on is still under development. I'll get back to you when it gets deployed.

I think it should works as well. Since the only different are oauth2 credentials and redirect_uri.

@lylo
Copy link

lylo commented Dec 4, 2023

I'm seeing a similar issue here (although I'm using standard Rails not React) when trying to use Google One Tap with Omniauth as per https://developers.google.com/identity/gsi/web/guides/display-button.

I'm using:

gem "omniauth-google-oauth2"
gem "omniauth-rails_csrf_protection"

My initializer is:

Rails.application.config.middleware.use OmniAuth::Builder do
  provider :google_oauth2,
           Rails.application.credentials.google.client_id,
           Rails.application.credentials.google.client_secret
           {
             provider_ignores_state: true
           }
end

And my view is:

      <script src="https://accounts.google.com/gsi/client" async></script>
      <div id="g_id_onload"
          data-client_id="<%= Rails.application.credentials.dig(:google, :client_id) %>"
          data-login_uri="<%= auth_callback_url(:google_oauth2) %>"
          data-auto_prompt="false">
      </div>
      <div class="g_id_signin"
          data-type="standard"
          data-size="large"
          data-theme="outline"
          data-text="sign_in_with"
          data-shape="rectangular"
          data-logo_alignment="left">
      </div>

The Google flow works but Omniauth complains when the callback is received:

Started POST "/auth/google_oauth2/callback" for ::1 at 2023-12-04 15:21:40 +0000
DEBUG -- omniauth: (google_oauth2) Callback phase initiated.
ERROR -- omniauth: (google_oauth2) Authentication failure! csrf_detected: OmniAuth::Strategies::OAuth2::CallbackError, csrf_detected | CSRF detected
ERROR -- omniauth: (google_oauth2) Authentication failure! invalid_credentials: OmniAuth::Strategies::OAuth2::CallbackError, csrf_detected | CSRF detected
ERROR -- omniauth: (google_oauth2) Authentication failure! csrf_detected | CSRF detected: OmniAuth::Strategies::OAuth2::CallbackError, csrf_detected | CSRF detected
OmniAuth::Strategies::OAuth2::CallbackError (csrf_detected | CSRF detected):

If I don't try and use the Google One Tap in this way:

<%= button_to "Log in with Google", google_auth_path, data: { turbo: false } %>

Then it works fine, no CSFR error at all. However, there is a subtle difference. When I use the standard button_to above, OmniAuth behaves differently:

Started POST "/auth/google_oauth2" for ::1 at 2023-12-04 15:26:38 +0000
DEBUG -- omniauth: (google_oauth2) Request phase initiated.
Started GET "/auth/google_oauth2/callback?state=[state]&code=[code]&scope=email+profile+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.email+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.profile+openid&authuser=0&prompt=consent" for ::1 at 2023-12-04 15:26:41 +0000
DEBUG -- omniauth: (google_oauth2) Callback phase initiated.
OAuth2::AccessToken.from_hash: `hash` contained more than one 'token' key (["access_token", "id_token"]); using "access_token".

As you can see there is the additional POST to /auth/google_ouath2 ("request phase initiated") which then results in a GET requests to the callback, not a POST.

If anyone has a workaround for this, I'd love to know.

Perhaps Omniauth is not (yet) compatible with Google One Tap sign in?

@zquestz
Copy link
Owner

zquestz commented May 6, 2024

@Gasol did it work in prod for you?

@andrer0cha
Copy link

Are there any news or solutions? I'm facing the same issue trying to run a react on rails app with Devise and omniauth.
I also tried using the npm library but it's not working.

@zquestz
Copy link
Owner

zquestz commented Oct 27, 2024

If two libraries are not working, it is very likely the google app is not configured correctly. Make sure your callback paths are correct.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants