All requests authenticating as `shopify-app-user` despite API token (begun Sept. 7th)
This is a REALLY odd situation I'm in, and it appeared out of nowhere starting September 7th.
I have created an extension for the Shopify POS, which needs to call some globalActions in the Gadget backend. It uses an API key I created with the role
shopify-pos-extension
, which has access to the needed actions (see the attached image) .
However, the POS extension is getting a GGT_PERMISSION_DENIED
403 response for all global actions it tries to invoke EXCEPT for my hasFeature
action, which is permitted for shopify-app-users
. I have experimented with adding and removing permissions from shopify-app-user
and have verified that all requests are being given this role when invoked from the POS extension, despite the fact that I am passing in the API key in the Authorization
header.
Here's what makes this problem especially weird:
- Everything in production was working as expected until September 7th, when suddenly all requests to prod from my client were being called as the shopify-app-users
role.
- Everything works correctly in the development environment, using the same role (and, of course, the dev-specific API key)
- The API key/role is respected when called with CURL
to hit the graphql endpoint directly:

18 Replies
This is how I am making the call from my client. And as a reminder, this application code works perfectly fine in the development environment!
@[Gadget] Antoine @[Gadget] Harry , I was combing through some other issues that felt related and it seems like you folks have some good insight into these kinds of issues! Would love your support if available.
Hello,
We are at the end of our week right now but I can give you a little information before we are off for the weekend.
When working with extensions that offer session tokens, if you have used a Gadget provider and are passing it a session token, that context will automatically be tacked on to the requests and the appropriate role will be assigned (in that case the
shopify-app-user
role). It is not recommended (actually we urge against it) that you use api key auth in a frontend as it can be used to make malicious calls to your api if an unintended user gains access to it.
A question for you, why are you not using the @gadgetinc/react
and @gadgetinc/shopify-extensions
packages instead of using useFetch? Also, why would you not want to use the shopify-app-users
role (more curious than anything here)?
Please note that it is against server rules to ping (@) Gadget employees unless its an emergency or we haven't responded within 24 hours of your message (during our 9-5 Mon-Fri EST work week).Ah my apologies, I'll refrain from using @ mentions frivilously. Just been banging my head against my keyboard for a few days on this one.
I'll try to migrate over to those packages and see if that resolves the issue! If that doesn't work, I'll at least have more info for you come Monday.
Thanks a bunch!
I've struggled with how to access gadget api in the extensions half a year ago, but I remembered that somewhere in one random video I saw it. And then managed to make it work.
I've never made POS extension, but it's an extension nonetheless.
1. Just added a screenshot of folder structure that I use.
Then in the api.js you need to import your apps client package that gadget provides I randomly found it's link here now: https://docs.gadget.dev/guides/plugins/shopify/frontends in the table it provides the second one is psecific to your application. For example if your project is called 'raydev'
it will be that's how the api connects to your actual models and other things in your app.
The api is used a little bit different in the extension code, but very similar to normal gadget app environment.
You can see the library they provide here. https://docs.gadget.dev/reference/react#gadgetinc-react
Here is the github gist with my code https://gist.github.com/pacifists/ae9c1ec47259b07cb6a6c06383976d4a
2. The very big struggle for ai agents was to create a correct <Provider> I think someone from the team help me to figure it out in the end. Because of how react components stack and pass along context. Even thought now it seems very simple π
3. As I'm coding using cursor agent I just usually throw these samples at it and say 'this is the right way to do it' adapt and modify my code and it figures it out.
Hope this helps, I remember struggled with it for a few days too π Until I got the different between the app and how it works in shopify extensions.

I would love for someone to do a Guide that shows just this, because when it was the first time it was a big struggle and not clear at all. (and now someone from the team will post a link with the exact guide that is already there.... :D)
@rayhanmemon hope this helps and I've went the way you try it π I have a full file of utils.js where I was trying to do exactly what you're doing - to use fetch over the network π only when showing you the code I've realised it's still there and not linked to anything anymore π So I feel your pain.
Thanks a bunch for the thorough help @rytisluko ! This is definitelty the right track.
I ended up using both the
@gadgetinc/shopify-extensions/react
and the generated @gadget-client/<my-app>
libraries to instantiate a gadget API client like so:
And provide this client to my POS UI extension components like so:
I am still facing one issue, however, similar to the one outlined in this thread: https://discord.com/channels/836317518595096598/1358871712619434014/1358876881440604452.
I have two environments, production
and development
. When I instantiate my gadgetApiClient with environment: 'production'
, like so:
It works perfectly.
But when I use environment: 'development'
, I get the error:
The JWT claims seem correct when decoded in jwt.io:
So I wonder what could be fishy about dev vs. prod here...Yeah that's out of my depth π happy it helped you move forward hope you find your solution
Do you mind making sure that the environment variable that you set on the client is correctly targeting your environment? If the session token sent doesn't match any shops that installed your app, the session token will be marked as invalid
So there are a number of things that can be the issue here. Could you please share the name of the application so that I can take a closer look?
Sure thing! The app's name in Gadget is
gift-receipts
Thanks for taking a look. I'm almost positive that the environment variable set in the POS client code is correctβI tried hard-coding it to 'development', plus the GGT_INVALID_SHOPIFY_SESSION_TOKEN
I pasted above was from the development environment itselfMight you also have an example traceId that I could take a look at? It would be on the request as
x-trace-id
or in the backend logs
What file is the relevant code in? I'm having a hard time finding the origin of the requestsSure thing. Here are some trace IDs you might find interesting:
c58a42bc467174d07bc657f06917f2a9
c58a42bc467174d07bc657f06917f2a9
56d69c85ae83de57a21ed6b464eae8d0
56d69c85ae83de57a21ed6b464eae8d0
And here's some relevant code in the client:
extensions/gift-receipts-pos-extension/src/api.ts
is where we define a couple of helpers for creating the gadget client and session token.
extensions/gift-receipts-pos-extension/src/targets/orderDetails/Modal.tsx
is an example of how an extension target uses the @gadgetinc/shopify-extensions/react
Provider.
extensions/gift-receipts-pos-extension/src/PostPurchaseModal.tsx
is an example of how the provided client is used to make requests to the Gadget backend.What store are you testing this on?
Thought that the logs would have that information but its not included
You said that you changed your code to use the Gadget provider but I'm seeing fetch requests. Have you possibly changed branches?
Have you checked what session.shopId is returning? You shared a JSON blob that has
shopId: 1
I think that the fact that you aren't using our provider is the biggest blocker for you right now
The thing for me right now is that I can't really determine which is the issue to tackle cause the message returned from an invalid auth header is the sameI am using it on the store:
QuickGift Receipts DEV
(https://quickgift-receipts-dev.myshopify.com). The app is installed on that store (see image below)
Also, would you be able to take another look at my development environment?
I took a look at the environment once again and confirmed that my extension code is up to date and that fetch is not being used anywhere.
Here's a snippet from the PostPurchaseModal, the function is called
fetchOrderItems
, but internally it's using the gadget api client
Might I ask where your Gadget provider is in the extension? I don't see it
Its crucial that you add the provider for requests to be set with the correct headers
Take a look at this template for example: https://github.com/gadget-inc/templates/tree/devaoc/wishlist-dx/shopify/wishlist-public-remix-ssr
Specifically this file: https://github.com/gadget-inc/templates/blob/devaoc/wishlist-dx/shopify/wishlist-public-remix-ssr/extensions/wishlist-account-ui/src/Wishlist.tsx
Each of your modals/targets need to have the provider since there's not one centralized spot where the application gets rendered
Yep, I believe it has been correctly added to all extension targets in the app:
extensions/gift-receipts-pos-extension/src/targets/orderDetails/Modal.tsx
extensions/gift-receipts-pos-extension/src/targets/postPurchase/Modal.tsx
extensions/gift-receipts-pos-extension/src/targets/smartGrid/Modal.tsx
And as a reminder, it's working perfectly fine against my production
environment! It's just the development
environment where I'm experiencing this problem, which makes it impossible to test changes prior to deployment...
I've tried renaming the development environment and using the new name, but no availI'm really having a hard time understanding why this is happening. Could you please share some network request data with me (DM it)
Sure. Right now, I test the POS extension on my phone via the Shopify POS App.
Is there a straightforward way for me to get you the network request data you need while testing on my phone?
Were you able to reproduce this bug on your end by the way? Just want to sanity check that this is really an issue. Because from what I can tell, it's all wired up correctly, the app is installed on the test store, etc.