Shopify/omniauth-shopify-oauth2

Users signing up gets redircted to /auth/failure?message=csrf_detected&strategy=shopify

ChristofferJoergensen opened this issue · 12 comments

I am redirecting my users to:

https://some-store.myshopify.com/admin/oauth/authorize?client_id=123&scope=read_orders,read_products&redirect_uri=https://my.domain.com/auth/shopify/callback

and after the user confirms the app he gets redirected back to:

https://my.domain.com/auth/shopify/callback?code=123&hmac=123&shop=some-store.myshopify.com&signature=123&timestamp=1464696912

The next thing I can see in my log is that my server is redirecting the user to:

https://my.domain.com/auth/failure?message=csrf_detected&strategy=shopify

I have no idea why this is happening, but I suspect that it is because of some failure that happens while I use this gem.

My setup is:

# -*- encoding : utf-8 -*-
Rails.application.config.middleware.use OmniAuth::Builder do
  provider :shopify, "key", "secret",
    scope: 'read_orders,read_products',
    setup: lambda { |env| params = Rack::Utils.parse_query(env['QUERY_STRING'])
                        env['omniauth.strategy'].options[:client_options][:site] = "http://#{params['shop']}" }
end

The method that transfer the user to his shop is:

    def create
        ShopifyAPI::Session.setup({:api_key => "key", :secret => "secret"})
        session         = ShopifyAPI::Session.new("#{params[:username]}.myshopify.com")
                # The callback URL I am using matches the one entered as Redirection URL in my Shopify partner account.
        redirect_to session.create_permission_url(["read_orders", "read_products"], "https://my.domain.com/auth/shopify/callback")
    end

And the method that received the callback looks like this

    def auth_callback
        ...
        omniauth = request.env['omniauth.auth']
        if omniauth && omniauth[:provider] && omniauth[:provider] == "shopify"
            username    = params[:shop].split(".").first
            token       = omniauth['credentials'].token
        end
        ...
    end

Any idea why this is happening?

The omniauth gem stores a state parameter in the user's session (this is a security feature of oauth). Make sure sessions work in your application, and make sure the content of the session survives the redirect to shopify and back.

Thank for your answer. However, something looks strange when I look closer at the logs. My app never writes which method is used to handle the callback. Check it out here:

Started GET "/auth/shopify/callback?code=123&hmac=123&shop=some-test-store.myshopify.com&signature=123&timestamp=1464700738" for 127.0.0.1 at 2016-05-31 15:18:58 +0200
Started GET "/auth/failure?message=csrf_detected&strategy=shopify" for 127.0.0.1 at 2016-05-31 15:18:59 +0200
 Processing by Webshops::ShopifyWebshopsController#auth_failure as HTML
  Parameters: {"message"=>"csrf_detected", "strategy"=>"shopify"}

The first request is handled by the oauth provider, in this case it's Shopify's strategy: https://github.com/Shopify/omniauth-shopify-oauth2/blob/master/lib/omniauth/strategies/shopify.rb which inherits from the OAuth2 strategy: https://github.com/intridea/omniauth-oauth2/blob/master/lib/omniauth/strategies/oauth2.rb

Hi again. I found out that downgrading to 1.1.6 helped. I will investigate why that is and post the solution later.

1.1.6 is missing a ton of security features that may put your users at risk. Make sure you at least implement the verifications listed here: https://help.shopify.com/api/guides/authentication/oauth#confirming-installation since all of these would be done by the omniauth-shopify-oauth2 gem in version 1.1.14, if you intend on running 1.1.6 then your app should implement these security checks.

@ChristofferJoergensen do you found any solution for this problem?

troex commented

I've had similar issue today, but I'm running Sinatra app.

My problem was that on initial auth request /auth/shopify?shop=aaa... session variables were not set because of invalid domain in Rack::Session::Cookie setting.

I guess that issue shouldn't raise when running Rails but worth checking.

orrd commented

When I ran into this issue it turned out it was because I needed to enable "Embed in Shopify admin" (go to the app's admin page on Shopify, go to Extensions, and make sure "Embed in Shopify admin" is enabled).

Bumping this old thread. I hit this error state frequently when accessing a Shopify app from my phone. This log is an example from services.shopify.io:
https://logs.shopify.io/en-US/app/search/search?sid=1551668205.8424_6376F8BF-5E5C-4E4C-9BF8-1E079BB8768F

Ideally, the shopify_app would at least provide a standard error page that allows you to reset the session. I always have to resort to clearly my Safari browser data for google and Shopify to get thing back to a known good state to be able to log in again.

FYI

It looks like the docs and the actual implementation have a mismatch and if you're using the create_permission_url method as recommended in the README for the shopify_api gem then you'd always get a CSRF failure unless you disable the check.

This PR adds support for it but hasn't been merged: Shopify/shopify-api-ruby#467

My workaround is to basically duplicate the contents of the method in the linked PR.

@markburns how do you use the state param? I still see csrf_detected, when I pass any string: eg

shopify_session.create_permission_url(["read_products", "read_orders", "write_products"], "http://localhost:3000/auth/shopify/callback", { state: 'Shop'})

hey @fogonthedowns - I ended up basically re-implementing the bits I needed in the linked PR in the app I was working on, as I didn't have time to try and see that PR through/help out. It does look like another similar version of it has been merged though, so I'd probably have a look at that one first and check if you can get it working using the actual gem.