nuxt-graphql-client icon indicating copy to clipboard operation
nuxt-graphql-client copied to clipboard

[Bug] Shopify GraphQL returns 403 after client side navigation

Open Baroshem opened this issue 3 years ago • 12 comments
trafficstars

Hi @Diizzayy !

I encountered a strange issue when working with your module (which is great BTW)

Everything works great when accessing the page from URL, but when I am doing a page transition (i.e. from Homepage to Product Page) I am getting a 403 on graphql.json. I am using the example with Shopify.

Have you encountered something like this already?

Baroshem avatar Jun 01 '22 08:06 Baroshem

Does your Shopify api require authentication?

I'm not certain but I suspect this may be an authentication issue, when interacting with a GraphQL API that requires authentication, by default tokens passed via config are only applied on server side to prevent the token being leaked client side.

Diizzayy avatar Jun 01 '22 09:06 Diizzayy

Looking at this issue, I suppose it does (like it cannot fetch the graphql json from shopify on the frontend due to lack of the token).

useAsyncData probably tries to fetch the same data on the frontend but fails due to not having the auth correctly served. I will take a look at it and let you know :)

Baroshem avatar Jun 01 '22 09:06 Baroshem

@Baroshem I'm interested to hear your findings. If our suspicions are correct you can have a look at retaining config level tokens to aid in debugging this issue

Diizzayy avatar Jun 01 '22 09:06 Diizzayy

Hey, it seems like I have to retain the token for client side data fetching. Do you know any approach that I could do to somehow force client side fetch through some kind of server middleware to not retain the token?

Basically what is happening that on client side navigation, the request to graphql.json is being triggered but because the token is applied only on the server side, this navigigation is failing with 403

Baroshem avatar Jun 01 '22 14:06 Baroshem

For now I will leave it as it is as I cannot find any workaround.

BTW, do you have any example of triggering mutation on the client side? Like adding product to cart by clicking a button on the product page?

In the docs I was only able to see examples of useAsyncData with queries

Baroshem avatar Jun 03 '22 11:06 Baroshem

@Baroshem

In the docs I was only able to see examples of useAsyncData with queries

I need to update the documentation with clearer examples for different use cases.

BTW, do you have any example of triggering mutation on the client side?

This can be achieved as explained below.

  • Given the following

Nuxt-app/queries/user.gql

mutation addUser($input: UserInput!) {
    addUser(input: $input) {
      uid
      role
      name
      email
      picture
    }
}

query getUsers {
    users {
        uid
        role
        name
        email
        picture
    }
}
  • Usage
<script lang="ts" setup>
// Everything here ( gql functions, their inputs and return types ) should be fully typed

async function addUser() {
  const { addUser } = await GqlAddUser({
    input: {
      name: 'John Doe',
      email: '[email protected]'
    }
  })

  // additonal logic
}

async function getUsers() {
  const { users } = await GqlGetUsers()

  return users
}
</script>

ps: the properties returned by gql functions are named based on the GraphQL operation name

Diizzayy avatar Jun 03 '22 12:06 Diizzayy

For now I will leave it as it is as I cannot find any workaround.

@Baroshem I'll look into a way to circumvent this case for instances where the GraphQL query should only be made in a secured environment (server side) to prevent private token usage.

As this use case isn't limited to this module, it would be good if we provide a first class workaround using the capabilities that Nuxt 3 offers

Diizzayy avatar Jun 03 '22 12:06 Diizzayy

That would be awesome @Diizzayy !

Thank you for the example and the explanation. In the upcoming days I will be releasing a video tutorial about Building Headless Commerce with Nuxt 3, Shopify and Tailwind, and I decided to use your module as it provides the best Developer Experience :)

Basically:

<script setup lang="ts">
const { data } = await useAsyncData('products', () => GqlProducts({ first: 3 }))
</script>

<template>
  <div>
    <HeroBanner />
    <ProductList :products="data.products.edges"/>
  </div>
</template>

I will let you know when the video will be released! :)

Baroshem avatar Jun 03 '22 13:06 Baroshem

@Baroshem I love that you're delving into creating video tutorial, those will definitely be a great help to many newcomers in the Nuxt community.

I'm looking forward to checking out the video when it's released 😁

it provides the best Developer Experience :)

I'm glad to hear that you're liking it, it's going to get even better from here.

Diizzayy avatar Jun 04 '22 11:06 Diizzayy

Btw, I have this issue on a local dev server, productions is statically generated and seems working well if I query data only in setup.

iBobik avatar Nov 11 '22 14:11 iBobik

@iBobik Have you attempted enabling the retainToken flag?

Diizzayy avatar Nov 11 '22 14:11 Diizzayy

@Diizzayy I does not want to expose this token to the frontend, I want to enforce SSR for this calls.

iBobik avatar Nov 13 '22 00:11 iBobik