Shopify / koa-shopify-auth

DEPRECATED Middleware to authenticate a Koa application with Shopify
MIT License
80 stars 63 forks source link

How to run this in a local dev environment with docker-compose and nginx reverse proxy #47

Closed hardnold closed 3 years ago

hardnold commented 3 years ago

Hi,

not really a general issue with the package, more a specific issue that arises in my local dockerized setup. I couldn't find any ressources on this, so I thought I might open up this thread to discuss this.

My app works perfectly in my production environment (docker / Kubernetes in Gcloud). However, because of the Shopify auth process, I didn't manage to run my app locally and being able to connect it to a shopify dev store for testing changes before committing them.

My local setup is as follows:

All of this works fine, however, I cannot install my local app inside a shopify dev-store. So far I identified the following problems:

  1. Traffic coming through my ngrok tunnel carries the ngrok-address as host-header and therefor my proxy does not properly distribute the traffic. I was able to solve this by chaning the host-header of the incoming traffic via ngrok.conf:
    host_header: shopify-app.local
  2. The same problem is arising vice versa: The host-header of the response is set to shopify-app.local. I was also able to change this to the ngrok address by using a location-directive on the proxy for my shopify-app.local response traffic
    add_header  Host  [NGROK_ADDRESS] always;
  3. Now the next (and hopefully final) issue arises from this package. In src/auth/oauth-query-string.ts the redirect_uri is built from the ctx.host property. The hostname of course is shopify-app.local (since I changed it in 1. via ngrok.conf) and not the ngrok-hostname which means, the redirect-uri is https://shopify-app.local/auth/callback.

Now it gets weird... I get different errors, each time I try to install the app.

Sometimes I end up on https://shopify-app.local/ with the following App-Bridge error:

AppBridgeError: APP::ERROR::INVALID_CONFIG: shopOrigin must be provided

Which probably means (assuming from this thread) the shopOrigin is not available. The shopOrigin gets extracted from the session and gets set as cookie. After redirecting to the local redirect_uri both are not available in that namespace which I assume causes the error message.

Another time I get (correctly?) redirected to [NGROK-ADDRESS]/auth?shop=my-local-store.myshopify.com (store-address changed) and receive the following error:

Expected a valid shop query parameter

which I don't understand, since it's obviously there.

Also another time I end up on the shop backend page which lists all the installed apps and there I get an error:

The app couldn’t be loaded

This app can’t load due to an issue with browser cookies. Try enabling cookies in your browser, switching to another browser
, or contacting the developer to get support.

(I'm using chrome and cookies are enabled)

Also another time I end up on this page https://shopify-app.local/auth/callback?code=[CODE_REMOVED]&hmac=[HMAC_REMOVED]&shop=my-local-store.myshopify.com&state=161278933272500&timestamp=1612789333 with the error

Request origin could not be verified

Since I get various different errors, it's very hard for me to analyze the problems.

My auth-middleware looks like this:

server.use(
    createShopifyAuth({
      apiKey : SHOPIFY_API_KEY,
      secret : SHOPIFY_API_SECRET_KEY,
      scopes : appScopes,
      async afterAuth(ctx) {
        const {shop, accessToken} = ctx.session
        ctx.cookies.set('shopOrigin', shop, {
          httpOnly : false,
          secure   : process.env.NODE_ENV === 'production',
          sameSite : 'none'
        })

        //webhook registrations removed to improve readability

        await insertScriptTag({shop, accessToken})

        // ctx.redirect('/')
        ctx.redirect(process.env.APP_URL) //this is the ngrok-address
      },
    }),
  )

I would be more than happy if someone has any advice for me on how to get my local app to communicate with shopify properly or what else I can do to track down the issues.

ankesh7 commented 3 years ago

@hardnold I would like to see your dockerized configuration to provide some solid directions however based on your issue I would try the following things:

  1. Remove nginx proxy and point ngrok traffic directly to your running container. This should be possible with running a standalone container or with docker-compose.
  2. As you mentioned in Step 3, try logging ctx.host property in src/auth/oauth-query-string.ts. The host value always has to be ngrok host (publicly reachable on the network) as the nonce that is generated by the library is set as cookie for this particular host and it cannot be accessed by any other host.
  3. Make sure you are correctly getting redirected to [NGROK-ADDRESS]/auth?shop=my-local-store.myshopify.com.
  4. Make sure your callbacks for handling after auths are also set to use NGROK address in App config on Partners
kato-takaomi-ams commented 3 years ago

I don't know if it's related. In my case, when running on API-Gateway behind AWS-Cloudfront (koa behind proxy), I needed the following settings:

AWS-Cloudfront(proxy)
add 'X-Forwarded-Host' header

Origin Custom Headers
Header Name [X-Forwarded-Host]  
Value [xxxxxx.cloudfront.net] (Proxy Host)

API-Gateway(koa)
set proxy flag

const app = new Koa({ proxy: true });

With this settings, 'X-Forwarded-Host' header value is set to ctx.host.

> console.log(ctx.host);
xxxxxx.cloudfront.net
hardnold commented 3 years ago

Thanks to both of you @kato-takaomi-ams @ankesh7 for your respsonses and sorry for my late reply, got busy with other stuff and now came back to try your recommendations. Both were helpful. This is what finally made it work:

first of all I had to add the proxy flag for koa: const server = new Koa({ proxy : true }), thanks to @kato-takaomi-ams for the hint. Then thanks to @ankesh7's hint number 2, I found out that my host header always had my local hostname as value. I changed my proxy configuration from add_header Host 375123480b10.eu.ngrok.io always; to proxy_set_header Host 375123480b10.eu.ngrok.io;

That did the trick. Thanks again to both of you

thecodepixi commented 3 years ago

This issue looks to have been resolved through some helpful comments (thank you!) so I'm going to go ahead and close this. However, if you still have issues with the library please feel free to open another issue!